Move Loop Location to Processors
[ardour.git] / libs / ardour / disk_writer.cc
index fa05516665fd734fd9e8ba7dac10af419031093a..c5c9beca36f222d515dd5c95162d1a7fad5150a0 100644 (file)
@@ -50,8 +50,6 @@ DiskWriter::DiskWriter (Session& s, string const & str, DiskIOProcessor::Flag f)
        , capture_start_sample (0)
        , capture_captured (0)
        , was_recording (false)
-       , adjust_capture_position (0)
-       , _capture_offset (0)
        , first_recordable_sample (max_samplepos)
        , last_recordable_sample (max_samplepos)
        , last_possibly_recording (0)
@@ -88,89 +86,79 @@ DiskWriter::set_write_source_name (string const & str)
 }
 
 void
-DiskWriter::check_record_status (samplepos_t transport_sample, bool can_record)
+DiskWriter::check_record_status (samplepos_t transport_sample, double speed, 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);
+       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.
-        */
+       /* merge together the 3 factors that affect record status, and compute what has changed. */
 
-       rolling = _session.transport_speed() != 0.0f;
-       possibly_recording = (rolling << 2) | ((int)record_enabled() << 1) | (int)can_record;
-       change = possibly_recording ^ last_possibly_recording;
+       possibly_recording = (speed != 0.0f ? 4 : 0)  | (record_enabled() ? 2 : 0) | (can_record ? 1 : 0);
 
        if (possibly_recording == last_possibly_recording) {
                return;
        }
 
-       const samplecnt_t existing_material_offset = _session.worst_playback_latency();
-
        if (possibly_recording == fully_rec_enabled) {
 
                if (last_possibly_recording == fully_rec_enabled) {
                        return;
                }
 
-               capture_start_sample = _session.transport_sample();
-               first_recordable_sample = capture_start_sample + _capture_offset;
-               last_recordable_sample = max_samplepos;
-
-                DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %7 (%9) FRF = %2 CSF = %4 CO = %5, EMO = %6 RD = %8 WOL %10 WTL %11\n",
-                                                                      name(), first_recordable_sample, last_recordable_sample, capture_start_sample,
-                                                                      _capture_offset,
-                                                                      existing_material_offset,
-                                                                      transport_sample,
-                                                                      _session.transport_sample(),
-                                                                      _session.worst_output_latency(),
-                                                                      _session.worst_track_latency()));
-
-
-                if (_alignment_style == ExistingMaterial) {
-                        first_recordable_sample += existing_material_offset;
-                        DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("\tshift FRF by EMO %1\n",
-                                                                              first_recordable_sample));
-                }
-
-               prepare_record_status (capture_start_sample);
-
-       } else {
+               Location* loc;
+               if  (_session.config.get_punch_in () && 0 != (loc = _session.locations()->auto_punch_location ())) {
+                       capture_start_sample = loc->start ();
+               } else {
+                       capture_start_sample = _session.transport_sample ();
+               }
 
-               if (last_possibly_recording == fully_rec_enabled) {
+               first_recordable_sample = capture_start_sample;
 
-                       /* we were recording last time */
+               if (_alignment_style == ExistingMaterial) {
+                       first_recordable_sample += _capture_offset + _playback_offset;
+               }
 
-                       if (change & transport_rolling) {
+               if  (_session.config.get_punch_out () && 0 != (loc = _session.locations()->auto_punch_location ())) {
+                       /* this freezes the punch-out point when starting to record.
+                        *
+                        * We should allow to move it or at least allow to disable punch-out
+                        * while rolling..
+                        */
+                       last_recordable_sample = loc->end ();
+                       if (_alignment_style == ExistingMaterial) {
+                               last_recordable_sample += _capture_offset + _playback_offset;
+                       }
+               } else {
+                       last_recordable_sample = max_samplepos;
+               }
 
-                               /* transport-change (stopped rolling): last_recordable_sample was set in ::prepare_to_stop(). We
-                                * had to set it there because we likely rolled past the stopping point to declick out,
-                                * and then backed up.
-                                */
+               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: @ %2 (STS: %3) CS:%4 FRS: %5 IL: %7, OL: %8 CO: %r9 PO: %10 WOL: %11 WIL: %12\n",
+                                                                     name(),
+                                                                     transport_sample,
+                                                                     _session.transport_sample(),
+                                                                                                                                                                                                                                       capture_start_sample,
+                                                                                                                                                                                                                                       first_recordable_sample,
+                                                                                                                                                                                                                                       last_recordable_sample,
+                                                                     _input_latency,
+                                                                     _output_latency,
+                                                                     _capture_offset,
+                                                                     _playback_offset,
+                                                                     _session.worst_output_latency(),
+                                                                     _session.worst_input_latency()));
 
-                       } else {
-                               /* punch out */
 
-                               last_recordable_sample = _session.transport_sample() + _capture_offset;
+               prepare_record_status (capture_start_sample);
 
-                               if (_alignment_style == ExistingMaterial) {
-                                       last_recordable_sample += existing_material_offset;
-                               }
-                       }
-               }
        }
 
        last_possibly_recording = possibly_recording;
 }
 
 void
-DiskWriter::calculate_record_range (Evoral::OverlapType ot, samplepos_t transport_sample, samplecnt_t nframes,
-                                   samplecnt_t & rec_nframes, samplecnt_t & rec_offset)
+DiskWriter::calculate_record_range (Evoral::OverlapType ot, samplepos_t transport_sample, samplecnt_t nframes, samplecnt_t & rec_nframes, samplecnt_t & rec_offset)
 {
        switch (ot) {
        case Evoral::OverlapNone:
@@ -212,32 +200,9 @@ DiskWriter::calculate_record_range (Evoral::OverlapType ot, samplepos_t transpor
                break;
        }
 
-        DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 rec? %2 @ %3 (for %4) FRF %5 LRF %6 : rf %7 @ %8\n",
-                                                              _name, enum_2_string (ot), transport_sample, nframes,
-                                                              first_recordable_sample, last_recordable_sample, rec_nframes, rec_offset));
-}
-
-void
-DiskWriter::prepare_to_stop (samplepos_t transport_sample, samplepos_t audible_sample)
-{
-       switch (_alignment_style) {
-       case ExistingMaterial:
-               last_recordable_sample = transport_sample + _capture_offset;
-               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable sample to %2 + %3 = %4\n", _name, transport_sample, _capture_offset, last_recordable_sample));
-               break;
-
-       case CaptureTime:
-               last_recordable_sample = audible_sample; // note that capture_offset is zero
-               /* we may already have captured audio before the last_recordable_sample (audible sample),
-                  so deal with this.
-               */
-               if (last_recordable_sample > capture_start_sample) {
-                       capture_captured = min (capture_captured, last_recordable_sample - capture_start_sample);
-               }
-               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose("%1: prepare to stop sets last recordable sample to audible sample @ %2\n", _name, audible_sample));
-               break;
-       }
-
+       DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1 rec? %2 @ %3 (for %4) FRF %5 LRF %6 : rf %7 @ %8\n",
+                                                             _name, enum_2_string (ot), transport_sample, nframes,
+                                                             first_recordable_sample, last_recordable_sample, rec_nframes, rec_offset));
 }
 
 void
@@ -293,31 +258,6 @@ DiskWriter::get_captured_samples (uint32_t n) const
        }
 }
 
-void
-DiskWriter::set_input_latency (samplecnt_t l)
-{
-       Processor::set_input_latency (l);
-       set_capture_offset ();
-}
-
-void
-DiskWriter::set_capture_offset ()
-{
-       switch (_alignment_style) {
-       case ExistingMaterial:
-               _capture_offset = _input_latency;
-               break;
-
-       case CaptureTime:
-       default:
-               _capture_offset = 0;
-               break;
-       }
-
-       DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: using input latency %4, capture offset set to %2 with style = %3\n", name(), _capture_offset, enum_2_string (_alignment_style), _input_latency));
-}
-
-
 void
 DiskWriter::set_align_style (AlignStyle a, bool force)
 {
@@ -327,15 +267,14 @@ DiskWriter::set_align_style (AlignStyle a, bool force)
 
        if ((a != _alignment_style) || force) {
                _alignment_style = a;
-               set_capture_offset ();
                AlignmentStyleChanged ();
        }
 }
 
 XMLNode&
-DiskWriter::state (bool full)
+DiskWriter::state ()
 {
-       XMLNode& node (DiskIOProcessor::state (full));
+       XMLNode& node (DiskIOProcessor::state ());
        node.set_property (X_("type"), X_("diskwriter"));
        node.set_property (X_("record-safe"), (_record_safe ? X_("yes" : "no")));
        return node;
@@ -369,10 +308,10 @@ DiskWriter::non_realtime_locate (samplepos_t position)
 
 
 void
-DiskWriter::prepare_record_status(samplepos_t capture_start_sample)
+DiskWriter::prepare_record_status (samplepos_t capture_start_sample)
 {
        if (recordable() && destructive()) {
-               boost::shared_ptr<ChannelList> c = channels.reader();
+               boost::shared_ptr<ChannelList> c = channels.reader ();
                for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
 
                        RingBufferNPT<CaptureTransition>::rw_vector transitions;
@@ -404,31 +343,33 @@ void
 DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_sample,
                  double speed, pframes_t nframes, bool result_required)
 {
+       if (!_active && !_pending_active) {
+               return;
+       }
+       _active = _pending_active;
+
        uint32_t n;
        boost::shared_ptr<ChannelList> c = channels.reader();
        ChannelList::iterator chan;
+
        samplecnt_t rec_offset = 0;
        samplecnt_t rec_nframes = 0;
        bool nominally_recording;
+
        bool re = record_enabled ();
+       bool punch_in = _session.config.get_punch_in () && _session.locations()->auto_punch_location ();
        bool can_record = _session.actively_recording ();
-
-       if (_active) {
-               if (!_pending_active) {
-                       _active = false;
-                       return;
-               }
-       } else {
-               if (_pending_active) {
-                       _active = true;
-               } else {
-                       return;
-               }
-       }
+       can_record |= speed != 0 && _session.get_record_enabled () && punch_in && _session.transport_sample () <= _session.locations()->auto_punch_location ()->start ();
 
        _need_butler = false;
 
-       check_record_status (start_sample, can_record);
+#ifndef NDEBUG
+       if (speed != 0 && re) {
+               DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("%1: run() start: %2 end: %3 NF: %4\n", _name, start_sample, end_sample, nframes));
+       }
+#endif
+
+       check_record_status (start_sample, speed, can_record);
 
        if (nframes == 0) {
                return;
@@ -443,18 +384,16 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                last_recordable_sample = max_samplepos;
        }
 
-       const Location* const loop_loc    = loop_location;
-       samplepos_t            loop_start  = 0;
-       samplepos_t            loop_end    = 0;
-       samplepos_t            loop_length = 0;
+       const Location* const loop_loc    = _loop_location;
+       samplepos_t           loop_start  = 0;
+       samplepos_t           loop_end    = 0;
+       samplepos_t           loop_length = 0;
 
        if (loop_loc) {
                get_location_times (loop_loc, &loop_start, &loop_end, &loop_length);
        }
 
-       adjust_capture_position = 0;
-
-       if (nominally_recording || (re && was_recording && _session.get_record_enabled() && (_session.config.get_punch_in() || _session.preroll_record_punch_enabled()))) {
+       if (nominally_recording || (re && was_recording && _session.get_record_enabled() && punch_in)) {
 
                Evoral::OverlapType ot = Evoral::coverage (first_recordable_sample, last_recordable_sample, start_sample, end_sample);
                // XXX should this be transport_sample + nframes - 1 ? coverage() expects its parameter ranges to include their end points
@@ -472,7 +411,7 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                                   at the loop start and can handle time wrapping around.
                                   Otherwise, start the source right now as usual.
                                */
-                               capture_captured    = start_sample - loop_start;
+                               capture_captured     = start_sample - loop_start;
                                capture_start_sample = loop_start;
                        }
 
@@ -480,8 +419,8 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                                _midi_write_source->mark_write_starting_now (capture_start_sample, capture_captured, loop_length);
                        }
 
-                       g_atomic_int_set(const_cast<gint*> (&_samples_pending_write), 0);
-                       g_atomic_int_set(const_cast<gint*> (&_num_captured_loops), 0);
+                       g_atomic_int_set (const_cast<gint*> (&_samples_pending_write), 0);
+                       g_atomic_int_set (const_cast<gint*> (&_num_captured_loops), 0);
 
                        was_recording = true;
 
@@ -499,7 +438,7 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
 
        }
 
-       if (can_record && !_last_capture_sources.empty()) {
+       if (can_record && !_last_capture_sources.empty ()) {
                _last_capture_sources.clear ();
        }
 
@@ -526,9 +465,9 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                                samplecnt_t total = chaninfo->rw_vector.len[0] + chaninfo->rw_vector.len[1];
 
                                if (rec_nframes > total) {
-                                        DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 overrun in %2, rec_nframes = %3 total space = %4\n",
-                                                                                    DEBUG_THREAD_SELF, name(), rec_nframes, total));
-                                        Overrun ();
+                                       DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 overrun in %2, rec_nframes = %3 total space = %4\n",
+                                                                                   DEBUG_THREAD_SELF, name(), rec_nframes, total));
+                                       Overrun ();
                                        return;
                                }
 
@@ -551,7 +490,7 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                MidiChannelFilter* filter = mt ? &mt->capture_filter() : 0;
 
                for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
-                       Evoral::Event<MidiBuffer::TimeType> ev(*i, false);
+                       Evoral::Event<MidiBuffer::TimeType> ev (*i, false);
                        if (ev.time() + rec_offset > rec_nframes) {
                                break;
                        }
@@ -586,11 +525,25 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
                                continue;
                        }
 
+                       bool skip_event = false;
+                       if (mt) {
+                               /* skip injected immediate/out-of-band events */
+                               MidiBuffer const& ieb (mt->immediate_event_buffer());
+                               for (MidiBuffer::const_iterator j = ieb.begin(); j != ieb.end(); ++j) {
+                                       if (*j == ev) {
+                                               skip_event = true;
+                                       }
+                               }
+                       }
+                       if (skip_event) {
+                               continue;
+                       }
+
                        if (!filter || !filter->filter(ev.buffer(), ev.size())) {
                                _midi_buf->write (event_time, ev.event_type(), ev.size(), ev.buffer());
                        }
                }
-               g_atomic_int_add(const_cast<gint*>(&_samples_pending_write), nframes);
+               g_atomic_int_add (const_cast<gint*>(&_samples_pending_write), nframes);
 
                if (buf.size() != 0) {
                        Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex, Glib::Threads::TRY_LOCK);
@@ -695,6 +648,16 @@ DiskWriter::finish_capture (boost::shared_ptr<ChannelList> c)
        first_recordable_sample = max_samplepos;
 }
 
+boost::shared_ptr<MidiBuffer>
+DiskWriter::get_gui_feed_buffer () const
+{
+       boost::shared_ptr<MidiBuffer> b (new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI)));
+
+       Glib::Threads::Mutex::Lock lm (_gui_feed_buffer_mutex);
+       b->copy (_gui_feed_buffer);
+       return b;
+}
+
 void
 DiskWriter::set_record_enabled (bool yn)
 {
@@ -1265,14 +1228,14 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo
                /* set length in beats to entire capture length */
 
                BeatsSamplesConverter converter (_session.tempo_map(), capture_info.front()->start);
-               const Evoral::Beats total_capture_beats = converter.from (total_capture);
+               const Temporal::Beats total_capture_beats = converter.from (total_capture);
                _midi_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.
                */
 
-               _midi_write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Evoral::Beats>::ResolveStuckNotes, total_capture_beats);
+               _midi_write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Temporal::Beats>::ResolveStuckNotes, total_capture_beats);
        }
 
        _last_capture_sources.insert (_last_capture_sources.end(), audio_srcs.begin(), audio_srcs.end());
@@ -1418,14 +1381,8 @@ DiskWriter::use_destructive_playlist ()
                assert((*chan)->write_source);
                (*chan)->write_source->set_allow_remove_if_empty (false);
 
-               /* this might be false if we switched modes, so force it */
-
-#ifdef XXX_OLD_DESTRUCTIVE_API_XXX
-               (*chan)->write_source->set_destructive (true);
-#else
                // should be set when creating the source or loading the state
                assert ((*chan)->write_source->destructive());
-#endif
        }
 
        /* the source list will never be reset for a destructive track */
@@ -1444,7 +1401,6 @@ DiskWriter::adjust_buffering ()
 void
 DiskWriter::realtime_handle_transport_stopped ()
 {
-       realtime_speed_change ();
 }
 
 bool