diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2019-11-22 23:41:56 -0700 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2019-11-22 23:41:56 -0700 |
commit | 1a2665e25fc8b01e2b7ca155259d53bc92c544b6 (patch) | |
tree | 1bbb91fbcdc1ee40c6586cc0890872b14681f611 /libs | |
parent | c456006f82086c0a976da99dc0f6db152d13322b (diff) |
redesign of declicking and fades around loop boundaries
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/disk_reader.h | 47 | ||||
-rw-r--r-- | libs/ardour/ardour/rc_configuration_vars.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/route.h | 2 | ||||
-rw-r--r-- | libs/ardour/ardour/session.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/track.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/transport_fsm.h | 6 | ||||
-rw-r--r-- | libs/ardour/ardour/types.h | 7 | ||||
-rw-r--r-- | libs/ardour/ardour/types_convert.h | 1 | ||||
-rw-r--r-- | libs/ardour/disk_reader.cc | 342 | ||||
-rw-r--r-- | libs/ardour/enums.cc | 9 | ||||
-rw-r--r-- | libs/ardour/route.cc | 5 | ||||
-rw-r--r-- | libs/ardour/session.cc | 24 | ||||
-rw-r--r-- | libs/ardour/session_transport.cc | 2 | ||||
-rw-r--r-- | libs/ardour/track.cc | 6 | ||||
-rw-r--r-- | libs/ardour/transport_fsm.cc | 22 |
15 files changed, 437 insertions, 39 deletions
diff --git a/libs/ardour/ardour/disk_reader.h b/libs/ardour/ardour/disk_reader.h index 427a6503d2..970295b6c2 100644 --- a/libs/ardour/ardour/disk_reader.h +++ b/libs/ardour/ardour/disk_reader.h @@ -22,6 +22,8 @@ #include "pbd/i18n.h" +#include "evoral/Curve.h" + #include "ardour/disk_io.h" #include "ardour/midi_buffer.h" #include "ardour/midi_state_tracker.h" @@ -53,6 +55,7 @@ public: void realtime_locate (bool); bool overwrite_existing_buffers (); void set_pending_overwrite (); + void set_loop (Location *); int set_state (const XMLNode&, int version); @@ -96,6 +99,7 @@ public: void reset_tracker (); bool declick_in_progress () const; + void reload_loop (); static void set_midi_readahead_samples (samplecnt_t samples_ahead) { midi_readahead = samples_ahead; } @@ -110,18 +114,30 @@ public: static void inc_no_disk_output (); static void dec_no_disk_output(); static bool no_disk_output () { return g_atomic_int_get (&_no_disk_output); } + static void reset_loop_declick (Location*, samplecnt_t sample_rate); + static void alloc_loop_declick (samplecnt_t sample_rate); protected: friend class Track; friend class MidiTrack; - struct ReaderChannelInfo : public DiskIOProcessor::ChannelInfo { - ReaderChannelInfo (samplecnt_t buffer_size) + struct ReaderChannelInfo : public DiskIOProcessor::ChannelInfo + { + ReaderChannelInfo (samplecnt_t buffer_size, samplecnt_t preloop_size) : DiskIOProcessor::ChannelInfo (buffer_size) + , pre_loop_buffer (0) + , pre_loop_buffer_size (0) { resize (buffer_size); + resize_preloop (preloop_size); } + ~ReaderChannelInfo() { delete [] pre_loop_buffer; } + void resize (samplecnt_t); + void resize_preloop (samplecnt_t); + + Sample* pre_loop_buffer; + samplecnt_t pre_loop_buffer_size; }; XMLNode& state (); @@ -138,7 +154,7 @@ protected: public: DeclickAmp (samplecnt_t sample_rate); - void apply_gain (AudioBuffer& buf, samplecnt_t n_samples, const float target); + void apply_gain (AudioBuffer& buf, samplecnt_t n_samples, const float target, sampleoffset_t buffer_offset = 0); float gain () const { return _g; } void set_gain (float g) { _g = g; } @@ -149,6 +165,22 @@ protected: float _g; }; + class Declicker { + public: + Declicker (); + ~Declicker (); + + void alloc (samplecnt_t sr, bool fadein); + + void run (Sample* buf, samplepos_t start, samplepos_t end); + void reset (samplepos_t start, samplepos_t end, bool fadein, samplecnt_t sr); + + samplepos_t fade_start; + samplepos_t fade_end; + samplecnt_t fade_length; + Sample* vec; + }; + private: /** The number of samples by which this diskstream's output should be delayed with respect to the transport sample. This is used for latency compensation. @@ -170,12 +202,18 @@ private: static samplecnt_t midi_readahead; static gint _no_disk_output; + static Declicker loop_declick_in; + static Declicker loop_declick_out; + static samplecnt_t loop_fade_length; + int audio_read (PBD::PlaybackBuffer<Sample>*, Sample* sum_buffer, Sample* mixdown_buffer, float* gain_buffer, samplepos_t& start, samplecnt_t cnt, - int channel, bool reversed); + ReaderChannelInfo* rci, + int channel, + bool reversed); static Sample* _sum_buffer; static Sample* _mixdown_buffer; @@ -189,6 +227,7 @@ private: RTMidiBuffer* rt_midibuffer(); void get_midi_playback (MidiBuffer& dst, samplepos_t start_sample, samplepos_t end_sample, MonitorState, BufferSet&, double speed, samplecnt_t distance); + void maybe_xfade_loop (Sample*, samplepos_t read_start, samplepos_t read_end, ReaderChannelInfo*); }; } // namespace diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h index 6938531b5e..b572bec865 100644 --- a/libs/ardour/ardour/rc_configuration_vars.h +++ b/libs/ardour/ardour/rc_configuration_vars.h @@ -162,6 +162,7 @@ CONFIG_VARIABLE (bool, create_xrun_marker, "create-xrun-marker", true) CONFIG_VARIABLE (bool, stop_at_session_end, "stop-at-session-end", false) CONFIG_VARIABLE (float, preroll_seconds, "preroll-seconds", -2.0f) CONFIG_VARIABLE (bool, loop_is_mode, "loop-is-mode", false) +CONFIG_VARIABLE (LoopFadeChoice, loop_fade_choice, "loop-fade-choice", XFadeLoop) CONFIG_VARIABLE (samplecnt_t, preroll, "preroll", 0) CONFIG_VARIABLE (samplecnt_t, postroll, "postroll", 0) CONFIG_VARIABLE (float, shuttle_speed_factor, "shuttle-speed-factor", 1.0f) // used for MMC shuttle diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index efc93a7ee9..5c2c4ad48d 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -360,6 +360,8 @@ public: PBD::Signal0<void> denormal_protection_changed; PBD::Signal0<void> comment_changed; + virtual void reload_loop(); + bool is_track(); /** track numbers - assigned by session diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 4e74a1dc5a..3a3f16dfdf 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -1486,7 +1486,6 @@ private: PBD::ScopedConnectionList loop_connections; void auto_loop_changed (Location *); - void auto_loop_declick_range (Location *, samplepos_t &, samplepos_t &); void pre_engine_init (std::string path); int post_engine_init (); diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index 90d5574b65..0b6462fbc3 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -166,6 +166,7 @@ public: } void adjust_playback_buffering (); void adjust_capture_buffering (); + void reload_loop (); PBD::Signal0<void> FreezeChange; PBD::Signal0<void> PlaylistChanged; diff --git a/libs/ardour/ardour/transport_fsm.h b/libs/ardour/ardour/transport_fsm.h index 7eafccead1..26ccb78765 100644 --- a/libs/ardour/ardour/transport_fsm.h +++ b/libs/ardour/ardour/transport_fsm.h @@ -54,7 +54,7 @@ struct TransportFSM }; /* for locate */ samplepos_t target; - bool with_loop; + bool for_loop_end; bool force; Event (EventType t) @@ -62,7 +62,7 @@ struct TransportFSM , with_roll (false) , with_flush (false) , target (0) - , with_loop (false) + , for_loop_end (false) , force (false) {} Event (EventType t, bool ab, bool cl) @@ -77,7 +77,7 @@ struct TransportFSM , with_roll (r) , with_flush (fl) , target (pos) - , with_loop (lp) + , for_loop_end (lp) , force (f4c) { assert (t == Locate); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index ea96c7fd6d..7cd3759a88 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -785,6 +785,13 @@ struct CaptureInfo { samplecnt_t samples; }; +enum LoopFadeChoice { + NoLoopFade, + EndLoopFade, + BothLoopFade, + XFadeLoop, +}; + typedef std::vector<CaptureInfo*> CaptureInfos; } // namespace ARDOUR diff --git a/libs/ardour/ardour/types_convert.h b/libs/ardour/ardour/types_convert.h index ae48c7602d..9e46d51982 100644 --- a/libs/ardour/ardour/types_convert.h +++ b/libs/ardour/ardour/types_convert.h @@ -75,6 +75,7 @@ DEFINE_ENUM_CONVERT(ARDOUR::VUMeterStandard) DEFINE_ENUM_CONVERT(ARDOUR::MeterLineUp) DEFINE_ENUM_CONVERT(ARDOUR::MidiPortFlags) DEFINE_ENUM_CONVERT(ARDOUR::TransportRequestType) +DEFINE_ENUM_CONVERT(ARDOUR::LoopFadeChoice) DEFINE_ENUM_CONVERT(MusicalMode::Type) diff --git a/libs/ardour/disk_reader.cc b/libs/ardour/disk_reader.cc index b62fe04ecd..b4ffba834e 100644 --- a/libs/ardour/disk_reader.cc +++ b/libs/ardour/disk_reader.cc @@ -23,6 +23,8 @@ #include "pbd/memento_command.h" #include "pbd/playback_buffer.h" +#include "evoral/Range.h" + #include "ardour/amp.h" #include "ardour/audioengine.h" #include "ardour/audioplaylist.h" @@ -52,6 +54,9 @@ Sample* DiskReader::_mixdown_buffer = 0; gain_t* DiskReader::_gain_buffer = 0; samplecnt_t DiskReader::midi_readahead = 4096; gint DiskReader::_no_disk_output (0); +DiskReader::Declicker DiskReader::loop_declick_in; +DiskReader::Declicker DiskReader::loop_declick_out; +samplecnt_t DiskReader::loop_fade_length (0); DiskReader::DiskReader (Session& s, string const & str, DiskIOProcessor::Flag f) : DiskIOProcessor (s, str, f) @@ -80,11 +85,25 @@ DiskReader::ReaderChannelInfo::resize (samplecnt_t bufsize) memset (rbuf->buffer(), 0, sizeof (Sample) * rbuf->bufsize()); } +void +DiskReader::ReaderChannelInfo::resize_preloop (samplecnt_t bufsize) +{ + if (bufsize == 0) { + return; + } + + if (bufsize > pre_loop_buffer_size) { + delete [] pre_loop_buffer; + pre_loop_buffer = new Sample[bufsize]; + pre_loop_buffer_size = bufsize; + } +} + int DiskReader::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many) { while (how_many--) { - c->push_back (new ReaderChannelInfo (_session.butler()->audio_diskstream_playback_buffer_size())); + c->push_back (new ReaderChannelInfo (_session.butler()->audio_diskstream_playback_buffer_size(), loop_fade_length)); DEBUG_TRACE (DEBUG::DiskIO, string_compose ("%1: new reader channel, write space = %2 read = %3\n", name(), c->back()->rbuf->write_space(), @@ -540,7 +559,9 @@ DiskReader::overwrite_existing_buffers () samplepos_t start = overwrite_sample; samplecnt_t to_read = size; - if (audio_read ((*chan)->rbuf, sum_buffer.get(), mixdown_buffer.get(), gain_buffer.get(), start, to_read, n, reversed)) { + ReaderChannelInfo* rci = dynamic_cast<ReaderChannelInfo*> (*chan); + + if (audio_read ((*chan)->rbuf, sum_buffer.get(), mixdown_buffer.get(), gain_buffer.get(), start, to_read, rci, n, reversed)) { error << string_compose(_("DiskReader %1: when refilling, cannot read %2 from playlist at sample %3"), id(), size, overwrite_sample) << endmsg; goto midi; } @@ -689,6 +710,7 @@ DiskReader::audio_read (PBD::PlaybackBuffer<Sample>*rb, Sample* mixdown_buffer, float* gain_buffer, samplepos_t& start, samplecnt_t cnt, + ReaderChannelInfo* rci, int channel, bool reversed) { samplecnt_t this_read = 0; @@ -758,11 +780,36 @@ DiskReader::audio_read (PBD::PlaybackBuffer<Sample>*rb, this_read = min (cnt, this_read); + /* note that the mixdown and gain buffers are purely for the + * internal use of the playlist, and cannot be considered + * useful after the return from AudioPlayback::read() + */ + if (audio_playlist()->read (sum_buffer, mixdown_buffer, gain_buffer, start, this_read, channel) != this_read) { error << string_compose(_("DiskReader %1: cannot read %2 from playlist at sample %3"), id(), this_read, start) << endmsg; return -1; } + if (loc) { + + /* Looping: do something (maybe) about the loop boundaries */ + + switch (Config->get_loop_fade_choice()) { + case NoLoopFade: + break; + case BothLoopFade: + loop_declick_in.run (sum_buffer, start, start + this_read); + loop_declick_out.run (sum_buffer, start, start + this_read); + break; + case EndLoopFade: + loop_declick_out.run (sum_buffer, start, start + this_read); + break; + case XFadeLoop: + maybe_xfade_loop (sum_buffer, start, start + this_read, rci); + break; + } + } + if (reversed) { swap_by_ptr (sum_buffer, sum_buffer + this_read - 1); @@ -968,7 +1015,8 @@ DiskReader::refill_audio (Sample* sum_buffer, Sample* mixdown_buffer, float* gai // cerr << owner()->name() << " to-read: " << to_read << endl; if (to_read) { - if (audio_read (chan->rbuf, sum_buffer, mixdown_buffer, gain_buffer, file_sample_tmp, to_read, chan_n, reversed)) { + ReaderChannelInfo* rci = dynamic_cast<ReaderChannelInfo*> (chan); + if (audio_read (chan->rbuf, sum_buffer, mixdown_buffer, gain_buffer, file_sample_tmp, to_read, rci, chan_n, reversed)) { error << string_compose(_("DiskReader %1: when refilling, cannot read %2 from playlist at sample %3"), id(), to_read, ffa) << endmsg; ret = -1; goto out; @@ -1236,7 +1284,7 @@ DiskReader::DeclickAmp::DeclickAmp (samplecnt_t sample_rate) } void -DiskReader::DeclickAmp::apply_gain (AudioBuffer& buf, samplecnt_t n_samples, const float target) +DiskReader::DeclickAmp::apply_gain (AudioBuffer& buf, samplecnt_t n_samples, const float target, sampleoffset_t buffer_offset) { if (n_samples == 0) { return; @@ -1244,6 +1292,7 @@ DiskReader::DeclickAmp::apply_gain (AudioBuffer& buf, samplecnt_t n_samples, con float g = _g; if (g == target) { + assert (buffer_offset == 0); Amp::apply_simple_gain (buf, n_samples, target, 0); return; } @@ -1253,7 +1302,7 @@ DiskReader::DeclickAmp::apply_gain (AudioBuffer& buf, samplecnt_t n_samples, con const int max_nproc = 16; uint32_t remain = n_samples; - uint32_t offset = 0; + uint32_t offset = buffer_offset; while (remain > 0) { uint32_t n_proc = remain > max_nproc ? max_nproc : remain; @@ -1280,6 +1329,232 @@ DiskReader::DeclickAmp::apply_gain (AudioBuffer& buf, samplecnt_t n_samples, con } } +DiskReader::Declicker::Declicker () + : fade_start (0) + , fade_end (0) + , fade_length (0) + , vec (0) +{ +} + +DiskReader::Declicker::~Declicker () +{ + delete vec; +} + +void +DiskReader::Declicker::alloc (samplecnt_t sr, bool fadein) +{ + delete [] vec; + vec = new Sample[loop_fade_length]; + + const float a = 1024.0f / sr; + + /* build a psuedo-exponential (linear-volume) shape for the fade */ + + samplecnt_t n; + +#define GAIN_COEFF_DELTA (1e-5) + + if (fadein) { + gain_t g = 0.0; + for (n = 0; (n < sr) && ((1.0 - g) > GAIN_COEFF_DELTA); ++n) { + vec[n] = g; + g += a * (1.0 - g); + } + } else { + gain_t g = 1.0; + for (n = 0; (n < sr) && (g > GAIN_COEFF_DELTA); ++n) { + vec[n] = g; + g += a * -g; + } + } + + fade_length = n; + + /* zero out the rest just to be safe */ + + memset (&vec[n], 0, sizeof (gain_t) * (loop_fade_length - n)); + +#undef GAIN_COEFF_DELTA +} + +void +DiskReader::Declicker::reset (samplepos_t loop_start, samplepos_t loop_end, bool fadein, samplecnt_t sr) +{ + if (loop_start == loop_end) { + fade_start = 0; + fade_end = 0; + return; + } + + /* adjust the position of the fade (this is absolute (global) timeline units) */ + + if (fadein) { + fade_start = loop_start; + fade_end = loop_start + fade_length; + } else { + fade_start = loop_end - fade_length; + fade_end = loop_end; + } + +} + +void +DiskReader::Declicker::run (Sample* buf, samplepos_t read_start, samplepos_t read_end) +{ + samplecnt_t n; /* how many samples to process */ + sampleoffset_t bo; /* offset into buffer */ + sampleoffset_t vo; /* offset into gain vector */ + + if (fade_start == fade_end) { + return; + } + + /* Determine how the read range overlaps with the fade range, so we can determine which part of the fade gain vector + to apply to which part of the buffer. + */ + + switch (Evoral::coverage (fade_start, fade_end, read_start, read_end)) { + + case Evoral::OverlapInternal: + /* note: start and end points cannot coincide (see evoral/Range.h) + * + * read range is entirely within fade range + */ + bo = 0; + vo = read_start - fade_start; + n = read_end - read_start; + break; + + case Evoral::OverlapExternal: + /* read range extends on either side of fade range + * + * External allows coincidental start & end points, so check for that + */ + if (fade_start == read_start && fade_end == read_end) { + /* fade entire read ... this is SO unlikely ! */ + bo = 0; + vo = 0; + n = fade_end - fade_start; + } else { + bo = fade_start - read_start; + vo = 0; + n = fade_end - fade_start; + } + break; + + case Evoral::OverlapStart: + /* read range starts before and ends within fade or at same end as fade */ + n = fade_end - read_start; + vo = 0; + bo = fade_start - read_start; + break; + + case Evoral::OverlapEnd: + /* read range starts within fade range, but possibly at it's end, so check */ + if (read_start == fade_end) { + /* nothing to do */ + return; + } + bo = 0; + vo = read_start - fade_start; + n = fade_end - read_start; + break; + + case Evoral::OverlapNone: + /* no overlap ... nothing to do */ + return; + } + + Sample* b = &buf[bo]; + gain_t* g = &vec[vo]; + + for (sampleoffset_t i = 0; i < n; ++i) { + b[i] *= g[i]; + } +} + +void +DiskReader::maybe_xfade_loop (Sample* buf, samplepos_t read_start, samplepos_t read_end, ReaderChannelInfo* chan) +{ + samplecnt_t n; /* how many samples to process */ + sampleoffset_t bo; /* offset into buffer */ + sampleoffset_t vo; /* offset into gain vector */ + + const samplepos_t fade_start = loop_declick_out.fade_start; + const samplepos_t fade_end = loop_declick_out.fade_end; + + if (fade_start == fade_end) { + return; + } + + /* Determine how the read range overlaps with the fade range, so we can determine which part of the fade gain vector + to apply to which part of the buffer. + */ + + switch (Evoral::coverage (fade_start, fade_end, read_start, read_end)) { + + case Evoral::OverlapInternal: + /* note: start and end points cannot coincide (see evoral/Range.h) + * + * read range is entirely within fade range + */ + bo = 0; + vo = read_start - fade_start; + n = read_end - read_start; + break; + + case Evoral::OverlapExternal: + /* read range extends on either side of fade range + * + * External allows coincidental start & end points, so check for that + */ + if (fade_start == read_start && fade_end == read_end) { + /* fade entire read ... this is SO unlikely ! */ + bo = 0; + vo = 0; + n = fade_end - fade_start; + } else { + bo = fade_start - read_start; + vo = 0; + n = fade_end - fade_start; + } + break; + + case Evoral::OverlapStart: + /* read range starts before and ends within fade or at same end as fade */ + n = fade_end - read_start; + vo = 0; + bo = fade_start - read_start; + break; + + case Evoral::OverlapEnd: + /* read range starts within fade range, but possibly at it's end, so check */ + if (read_start == fade_end) { + /* nothing to do */ + return; + } + bo = 0; + vo = read_start - fade_start; + n = fade_end - read_start; + break; + + case Evoral::OverlapNone: + /* no overlap ... nothing to do */ + return; + } + + Sample* b = &buf[bo]; /* data to be faded out */ + Sample* sbuf = &chan->pre_loop_buffer[vo]; /* pre-loop (maybe silence) to be faded in */ + gain_t* og = &loop_declick_out.vec[vo]; /* fade out gain vector */ + gain_t* ig = &loop_declick_in.vec[vo]; /* fade in gain vector */ + + for (sampleoffset_t i = 0; i < n; ++i) { + b[i] = (b[i] * og[i]) + (sbuf[i] * ig[i]); + } +} + RTMidiBuffer* DiskReader::rt_midibuffer () { @@ -1298,3 +1573,60 @@ DiskReader::rt_midibuffer () return mpl->rendered(); } + +void +DiskReader::alloc_loop_declick (samplecnt_t sr) +{ + loop_fade_length = lrintf (ceil (-log (1e-5) / (1024.f/sr))); + loop_declick_in.alloc (sr, true); + loop_declick_out.alloc (sr, false); +} + +void +DiskReader::reset_loop_declick (Location* loc, samplecnt_t sr) +{ + if (loc) { + loop_declick_in.reset (loc->start(), loc->end(), true, sr); + loop_declick_out.reset (loc->start(), loc->end(), false, sr); + } else { + loop_declick_in.reset (0, 0, true, sr); + loop_declick_out.reset (0, 0, false, sr); + } +} + +void +DiskReader::set_loop (Location* loc) +{ + Processor::set_loop (loc); + + if (!loc) { + return; + } + + reload_loop (); +} + +void +DiskReader::reload_loop () +{ + Location* loc = _loop_location; + boost::scoped_array<Sample> mix_buf (new Sample [loop_fade_length]); + boost::scoped_array<Sample> gain_buf (new Sample [loop_fade_length]); + + boost::shared_ptr<ChannelList> c = channels.reader(); + uint32_t channel = 0; + + for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan, ++channel) { + + ReaderChannelInfo* rci = dynamic_cast<ReaderChannelInfo*> (*chan); + + rci->resize_preloop (loop_fade_length); + + if (loc->start() > loop_fade_length) { + audio_playlist()->read (rci->pre_loop_buffer, mix_buf.get(), gain_buf.get(), loc->start() - loop_declick_out.fade_length, loop_declick_out.fade_length, channel); + } else { + memset (rci->pre_loop_buffer, 0, sizeof (Sample) * loop_fade_length); + } + + } +} diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index f374d70e75..67337ab9e5 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -155,7 +155,8 @@ setup_enum_writer () TransportFSM::EventType _TransportFSM_EventType; TransportFSM::MotionState _TransportFSM_MotionState; TransportFSM::ButlerState _TransportFSM_ButlerState; - + LoopFadeChoice _LoopFadeChooice; + #define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear() #define REGISTER_BITS(e) enum_writer.register_bits (typeid(e).name(), i, s); i.clear(); s.clear() #define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e) @@ -819,6 +820,12 @@ setup_enum_writer () REGISTER_CLASS_ENUM (TransportFSM, NotWaitingForButler); REGISTER_CLASS_ENUM (TransportFSM, WaitingForButler); REGISTER (_TransportFSM_ButlerState); + + REGISTER_ENUM (NoLoopFade); + REGISTER_ENUM (EndLoopFade); + REGISTER_ENUM (BothLoopFade); + REGISTER_ENUM (XFadeLoop); + REGISTER (_LoopFadeChooice); } } /* namespace ARDOUR */ diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index b48b18b305..15a609dbfd 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -6051,3 +6051,8 @@ Route::monitoring_state () const return get_auto_monitoring_state(); } + +void +Route::reload_loop () +{ +} diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 073ad07961..79bf3b31e2 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -1408,17 +1408,6 @@ Session::auto_punch_changed (Location* location) auto_punch_end_changed (location); } -/** @param loc A loop location. - * @param pos Filled in with the start time of the required fade-out (in session samples). - * @param length Filled in with the length of the required fade-out. - */ -void -Session::auto_loop_declick_range (Location* loc, samplepos_t & pos, samplepos_t & length) -{ - pos = max (loc->start(), loc->end() - 64); - length = loc->end() - pos; -} - void Session::auto_loop_changed (Location* location) { @@ -1430,6 +1419,12 @@ Session::auto_loop_changed (Location* location) if (play_loop) { + boost::shared_ptr<RouteList> r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + (*i)->reload_loop (); + } + if (_transport_sample < location->start() || _transport_sample > location->end()) { // new loop range excludes current transport // sample => relocate to beginning of loop and roll. @@ -1534,9 +1529,6 @@ Session::set_auto_loop_location (Location* location) loop_connections.drop_connections (); existing->set_auto_loop (false, this); remove_event (existing->end(), SessionEvent::AutoLoop); - samplepos_t dcp; - samplecnt_t dcl; - auto_loop_declick_range (existing, dcp, dcl); auto_loop_location_changed (0); } @@ -1972,6 +1964,10 @@ Session::set_sample_rate (samplecnt_t frames_per_second) clear_clicks (); reset_write_sources (false); + DiskReader::alloc_loop_declick (nominal_sample_rate()); + Location* loc = _locations->auto_loop_location (); + DiskReader::reset_loop_declick (loc, nominal_sample_rate()); + // XXX we need some equivalent to this, somehow // SndFileSource::setup_standard_crossfades (frames_per_second); diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 116091db18..e61e8fee59 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -1675,6 +1675,8 @@ Session::set_track_loop (bool yn) (*i)->set_loop (yn ? loc : 0); } } + + DiskReader::reset_loop_declick (loc, nominal_sample_rate()); } samplecnt_t diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc index 9e43635a24..e9c29ffa83 100644 --- a/libs/ardour/track.cc +++ b/libs/ardour/track.cc @@ -572,6 +572,12 @@ Track::set_slaved (bool s) _disk_writer->set_slaved (s); } +void +Track::reload_loop () +{ + _disk_reader->reload_loop (); +} + ChanCount Track::n_channels () { diff --git a/libs/ardour/transport_fsm.cc b/libs/ardour/transport_fsm.cc index d1a56cf101..5466192b33 100644 --- a/libs/ardour/transport_fsm.cc +++ b/libs/ardour/transport_fsm.cc @@ -151,8 +151,8 @@ a_row < Stopped, locate, WaitingForLocate, &T::start_locat g_row < WaitingForLocate, locate_done, Stopped, &T::should_not_roll_after_locate >, _row < Rolling, butler_done, Rolling >, _row < Rolling, start_transport, Rolling >, -a_row < Rolling, stop_transport, DeclickToStop, &T::start_declick_for_stop >, -a_row < DeclickToStop, declick_done, Stopped, &T::stop_playback >, +a_row < Rolling, stop_transport, DeclickToStop, &T::stop_playback >, +a_row < DeclickToStop, declick_done, Stopped, >, a_row < Rolling, locate, DeclickToLocate, &T::start_declick_for_locate >, a_row < DeclickToLocate, declick_done, WaitingForLocate, &T::start_locate_after_declick >, row < WaitingForLocate, locate_done, Rolling, &T::roll_after_locate, &T::should_roll_after_locate >, @@ -253,7 +253,7 @@ TransportFSM::process_event (Event& ev, bool already_deferred, bool& deferred) ev.with_roll, ev.with_flush, ev.target, - ev.with_loop, + ev.for_loop_end, ev.force)); switch (_motion_state) { case Stopped: @@ -261,7 +261,7 @@ TransportFSM::process_event (Event& ev, bool already_deferred, bool& deferred) start_locate_while_stopped (ev); break; case Rolling: - if (ev.with_loop) { + if (ev.for_loop_end) { /* we will finish the locate synchronously, so * that after returning from * ::locate_for_loop() we will already have @@ -407,17 +407,17 @@ TransportFSM::start_locate_while_stopped (Event const & l) const set_roll_after (l.with_roll); - api->locate (l.target, current_roll_after_locate_status.get(), l.with_flush, l.with_loop, l.force); + api->locate (l.target, current_roll_after_locate_status.get(), l.with_flush, l.for_loop_end, l.force); } void TransportFSM::locate_for_loop (Event const & l) { assert (l.type == Locate); - DEBUG_TRACE (DEBUG::TFSMEvents, string_compose ("locate_for_loop, wl = %1\n", l.with_loop)); + DEBUG_TRACE (DEBUG::TFSMEvents, string_compose ("locate_for_loop, wl = %1\n", l.for_loop_end)); set_roll_after (l.with_roll); _last_locate = l; - api->locate (l.target, l.with_roll, l.with_flush, l.with_loop, l.force); + api->locate (l.target, l.with_roll, l.with_flush, l.for_loop_end, l.force); } void @@ -427,7 +427,7 @@ TransportFSM::start_locate_after_declick () const current_roll_after_locate_status ? current_roll_after_locate_status.get() : _last_locate.with_roll)); const bool roll = current_roll_after_locate_status ? current_roll_after_locate_status.get() : _last_locate.with_roll; - api->locate (_last_locate.target, roll, _last_locate.with_flush, _last_locate.with_loop, _last_locate.force); + api->locate (_last_locate.target, roll, _last_locate.with_flush, _last_locate.for_loop_end, _last_locate.force); } void @@ -455,7 +455,7 @@ TransportFSM::interrupt_locate (Event const & l) const /* maintain original "with-roll" choice of initial locate, even though * we are interrupting the locate to start a new one. */ - api->locate (l.target, false, l.with_flush, l.with_loop, l.force); + api->locate (l.target, false, l.with_flush, l.for_loop_end, l.force); } void @@ -482,9 +482,9 @@ TransportFSM::should_roll_after_locate () const void TransportFSM::roll_after_locate () const { - DEBUG_TRACE (DEBUG::TFSMEvents, string_compose ("rolling after locate, was for_loop ? %1\n", _last_locate.with_loop)); + DEBUG_TRACE (DEBUG::TFSMEvents, string_compose ("rolling after locate, was for_loop ? %1\n", _last_locate.for_loop_end)); current_roll_after_locate_status = boost::none; - if (!_last_locate.with_loop) { + if (!_last_locate.for_loop_end) { api->start_transport (); } } |