libardour: conversion to use timeline types (mega-commit)

This commit is contained in:
Paul Davis 2020-09-20 16:34:09 -06:00
parent bca8e2e8cc
commit eae9d276fe
131 changed files with 2088 additions and 2856 deletions

View file

@ -103,7 +103,7 @@ Analyser::work ()
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src); boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
if (afs && afs->length(afs->natural_position())) { if (afs && !afs->empty()) {
Glib::Threads::Mutex::Lock lm (analysis_active_lock); Glib::Threads::Mutex::Lock lm (analysis_active_lock);
analyse_audio_file_source (afs); analyse_audio_file_source (afs);
} }

View file

@ -76,23 +76,24 @@ AnalysisGraph::analyze_region (AudioRegion const* region, bool raw, ARDOUR::Prog
_session->nominal_sample_rate(), _session->nominal_sample_rate(),
n_channels, n_channels,
n_samples, n_samples,
region->length())); region->length_samples()));
interleaver->add_output(chunker); interleaver->add_output(chunker);
chunker->add_output (analyser); chunker->add_output (analyser);
samplecnt_t x = 0; samplecnt_t x = 0;
samplecnt_t length = region->length(); samplecnt_t length = region->length_samples();
while (x < length) { while (x < length) {
samplecnt_t chunk = std::min (_max_chunksize, length - x); samplecnt_t chunk = std::min (_max_chunksize, length - x);
samplecnt_t n = 0; samplecnt_t n = 0;
for (unsigned int channel = 0; channel < region->n_channels(); ++channel) { for (unsigned int channel = 0; channel < region->n_channels(); ++channel) {
memset (_buf, 0, chunk * sizeof (Sample)); memset (_buf, 0, chunk * sizeof (Sample));
if (raw) { if (raw) {
n = region->read_raw_internal (_buf, region->start() + x, chunk, channel); n = region->read_raw_internal (_buf, region->start_sample() + x, chunk, channel);
} else { } else {
n = region->read_at (_buf, _mixbuf, _gainbuf, region->position() + x, chunk, channel); n = region->read_at (_buf, _mixbuf, _gainbuf, region->position_sample() + x, chunk, channel);
} }
ConstProcessContext<Sample> context (_buf, n, 1); ConstProcessContext<Sample> context (_buf, n, 1);
if (n < _max_chunksize) { if (n < _max_chunksize) {
context().set_flag (ProcessContext<Sample>::EndOfInput); context().set_flag (ProcessContext<Sample>::EndOfInput);
@ -121,7 +122,7 @@ AnalysisGraph::analyze_region (AudioRegion const* region, bool raw, ARDOUR::Prog
} }
void void
AnalysisGraph::analyze_range (boost::shared_ptr<Route> route, boost::shared_ptr<AudioPlaylist> pl, const std::list<AudioRange>& range) AnalysisGraph::analyze_range (boost::shared_ptr<Route> route, boost::shared_ptr<AudioPlaylist> pl, const std::list<TimelineRange>& range)
{ {
const uint32_t n_audio = route->n_inputs().n_audio(); const uint32_t n_audio = route->n_inputs().n_audio();
if (n_audio == 0 || n_audio > _max_chunksize) { if (n_audio == 0 || n_audio > _max_chunksize) {
@ -129,7 +130,7 @@ AnalysisGraph::analyze_range (boost::shared_ptr<Route> route, boost::shared_ptr<
} }
const samplecnt_t n_samples = _max_chunksize - (_max_chunksize % n_audio); const samplecnt_t n_samples = _max_chunksize - (_max_chunksize % n_audio);
for (std::list<AudioRange>::const_iterator j = range.begin(); j != range.end(); ++j) { for (std::list<TimelineRange>::const_iterator j = range.begin(); j != range.end(); ++j) {
interleaver.reset (new Interleaver<Sample> ()); interleaver.reset (new Interleaver<Sample> ());
interleaver->init (n_audio, _max_chunksize); interleaver->init (n_audio, _max_chunksize);
@ -137,17 +138,21 @@ AnalysisGraph::analyze_range (boost::shared_ptr<Route> route, boost::shared_ptr<
chunker.reset (new Chunker<Sample> (n_samples)); chunker.reset (new Chunker<Sample> (n_samples));
analyser.reset (new Analyser ( analyser.reset (new Analyser (
_session->nominal_sample_rate(), _session->nominal_sample_rate(),
n_audio, n_samples, (*j).length())); n_audio, n_samples, (*j).length_samples()));
interleaver->add_output(chunker); interleaver->add_output(chunker);
chunker->add_output (analyser); chunker->add_output (analyser);
samplecnt_t x = 0; samplecnt_t x = 0;
while (x < j->length()) { const samplecnt_t rlen = j->length().samples();
samplecnt_t chunk = std::min (_max_chunksize, (*j).length() - x); const samplepos_t rpos = j->start().samples();
while (x < rlen) {
samplecnt_t chunk = std::min (_max_chunksize, rlen - x);
samplecnt_t n = 0; samplecnt_t n = 0;
for (uint32_t channel = 0; channel < n_audio; ++channel) { for (uint32_t channel = 0; channel < n_audio; ++channel) {
n = pl->read (_buf, _mixbuf, _gainbuf, (*j).start + x, chunk, channel); n = pl->read (_buf, _mixbuf, _gainbuf, timepos_t (rpos + x), timecnt_t (chunk), channel).samples();
ConstProcessContext<Sample> context (_buf, n, 1); ConstProcessContext<Sample> context (_buf, n, 1);
if (n < _max_chunksize) { if (n < _max_chunksize) {
@ -165,11 +170,11 @@ AnalysisGraph::analyze_range (boost::shared_ptr<Route> route, boost::shared_ptr<
std::string name = string_compose (_("%1 (%2..%3)"), route->name(), std::string name = string_compose (_("%1 (%2..%3)"), route->name(),
Timecode::timecode_format_sampletime ( Timecode::timecode_format_sampletime (
(*j).start, rpos,
_session->nominal_sample_rate(), _session->nominal_sample_rate(),
100, false), 100, false),
Timecode::timecode_format_sampletime ( Timecode::timecode_format_sampletime (
(*j).start + (*j).length(), (*j).end().samples(),
_session->nominal_sample_rate(), _session->nominal_sample_rate(),
100, false) 100, false)
); );

View file

@ -48,7 +48,8 @@ class LIBARDOUR_API AnalysisGraph {
void analyze_region (ARDOUR::AudioRegion const*, bool raw = false, ARDOUR::Progress* = 0); void analyze_region (ARDOUR::AudioRegion const*, bool raw = false, ARDOUR::Progress* = 0);
void analyze_region (boost::shared_ptr<ARDOUR::AudioRegion>, bool raw = false); void analyze_region (boost::shared_ptr<ARDOUR::AudioRegion>, bool raw = false);
void analyze_range (boost::shared_ptr<ARDOUR::Route>, boost::shared_ptr<ARDOUR::AudioPlaylist>, const std::list<AudioRange>&); void analyze_range (boost::shared_ptr<ARDOUR::Route>, boost::shared_ptr<ARDOUR::AudioPlaylist>, const std::list<TimelineRange>&);
const AnalysisResults& results () const { return _results; } const AnalysisResults& results () const { return _results; }
void cancel () { _canceled = true; } void cancel () { _canceled = true; }

View file

@ -51,13 +51,13 @@ public:
int set_state (const XMLNode&, int version); int set_state (const XMLNode&, int version);
bool can_truncate_peaks() const { return false; } bool can_truncate_peaks() const { return false; }
bool can_be_analysed() const { return _length > 0; } bool can_be_analysed() const { return _length.positive(); }
protected: protected:
friend class SourceFactory; friend class SourceFactory;
AudioPlaylistSource (Session&, const PBD::ID& orig, const std::string& name, boost::shared_ptr<AudioPlaylist>, uint32_t chn, AudioPlaylistSource (Session&, const PBD::ID& orig, const std::string& name, boost::shared_ptr<AudioPlaylist>, uint32_t chn,
sampleoffset_t begin, samplecnt_t len, Source::Flag flags); timepos_t const & begin, timepos_t const & len, Source::Flag flags);
AudioPlaylistSource (Session&, const XMLNode&); AudioPlaylistSource (Session&, const XMLNode&);

View file

@ -30,7 +30,7 @@
namespace ARDOUR { namespace ARDOUR {
class Readable; class AudioReadable;
class Session; class Session;
class LIBARDOUR_API AudioAnalyser : public boost::noncopyable { class LIBARDOUR_API AudioAnalyser : public boost::noncopyable {
@ -44,7 +44,7 @@ class LIBARDOUR_API AudioAnalyser : public boost::noncopyable {
/* analysis object should provide a run method /* analysis object should provide a run method
that accepts a path to write the results to (optionally empty) that accepts a path to write the results to (optionally empty)
a Readable* to read data from a AudioReadable* to read data from
and a reference to a type-specific container to return the and a reference to a type-specific container to return the
results. results.
*/ */
@ -60,7 +60,7 @@ class LIBARDOUR_API AudioAnalyser : public boost::noncopyable {
samplecnt_t stepsize; samplecnt_t stepsize;
int initialize_plugin (AnalysisPluginKey name, float sample_rate); int initialize_plugin (AnalysisPluginKey name, float sample_rate);
int analyse (const std::string& path, Readable*, uint32_t channel); int analyse (const std::string& path, AudioReadable*, uint32_t channel);
/* instances of an analysis object will have this method called /* instances of an analysis object will have this method called
whenever there are results to process. if out is non-null, whenever there are results to process. if out is non-null,

View file

@ -70,7 +70,7 @@ public:
int set_state (const XMLNode&, int version); int set_state (const XMLNode&, int version);
bool can_truncate_peaks() const { return true; } bool can_truncate_peaks() const { return true; }
bool can_be_analysed() const { return _length > 0; } bool can_be_analysed() const { return _length.positive(); }
static bool safe_audio_file_extension (const std::string& path); static bool safe_audio_file_extension (const std::string& path);

View file

@ -41,9 +41,9 @@ public:
AudioPlaylist (Session&, const XMLNode&, bool hidden = false); AudioPlaylist (Session&, const XMLNode&, bool hidden = false);
AudioPlaylist (Session&, std::string name, bool hidden = false); AudioPlaylist (Session&, std::string name, bool hidden = false);
AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, std::string name, bool hidden = false); AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, std::string name, bool hidden = false);
AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, samplepos_t start, samplecnt_t cnt, std::string name, bool hidden = false); AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, timepos_t const & start, timepos_t const & cnt, std::string name, bool hidden = false);
samplecnt_t read (Sample *dst, Sample *mixdown, float *gain_buffer, samplepos_t start, samplecnt_t cnt, uint32_t chan_n=0); timecnt_t read (Sample *dst, Sample *mixdown, float *gain_buffer, timepos_t const & start, timecnt_t const & cnt, uint32_t chan_n=0);
bool destroy_region (boost::shared_ptr<Region>); bool destroy_region (boost::shared_ptr<Region>);

View file

@ -62,7 +62,7 @@ class Filter;
class AudioSource; class AudioSource;
class LIBARDOUR_API AudioRegion : public Region class LIBARDOUR_API AudioRegion : public Region, public AudioReadable
{ {
public: public:
static void make_property_quarks (); static void make_property_quarks ();
@ -104,26 +104,28 @@ class LIBARDOUR_API AudioRegion : public Region
boost::shared_ptr<AutomationList> inverse_fade_out() { return _inverse_fade_out.val (); } boost::shared_ptr<AutomationList> inverse_fade_out() { return _inverse_fade_out.val (); }
boost::shared_ptr<AutomationList> envelope() { return _envelope.val (); } boost::shared_ptr<AutomationList> envelope() { return _envelope.val (); }
Evoral::Range<samplepos_t> body_range () const; Temporal::Range body_range () const;
virtual samplecnt_t read_peaks (PeakData *buf, samplecnt_t npeaks, virtual samplecnt_t read_peaks (PeakData *buf, samplecnt_t npeaks,
samplecnt_t offset, samplecnt_t cnt, samplecnt_t offset, samplecnt_t cnt,
uint32_t chan_n=0, double samples_per_pixel = 1.0) const; uint32_t chan_n=0, double samples_per_pixel = 1.0) const;
/* Readable interface */ /* AudioReadable interface */
virtual samplecnt_t read (Sample*, samplepos_t pos, samplecnt_t cnt, int channel) const; samplecnt_t read (Sample*, samplepos_t pos, samplecnt_t cnt, int channel) const;
samplecnt_t readable_length_samples() const { return length_samples(); }
uint32_t n_channels() const { return _sources.size(); }
virtual samplecnt_t read_at (Sample *buf, Sample *mixdown_buf, float *gain_buf, samplecnt_t read_at (Sample *buf, Sample *mixdown_buf, float *gain_buf,
samplepos_t position, samplepos_t position,
samplecnt_t cnt, samplecnt_t cnt,
uint32_t chan_n = 0) const; uint32_t chan_n = 0) const;
virtual samplecnt_t master_read_at (Sample *buf, Sample *mixdown_buf, float *gain_buf, samplecnt_t master_read_at (Sample *buf, Sample *mixdown_buf, float *gain_buf,
samplepos_t position, samplecnt_t cnt, samplepos_t position, samplecnt_t cnt,
uint32_t chan_n=0) const; uint32_t chan_n=0) const;
virtual samplecnt_t read_raw_internal (Sample*, samplepos_t, samplecnt_t, int channel) const; samplecnt_t read_raw_internal (Sample*, samplepos_t, samplecnt_t, int channel) const;
XMLNode& state (); XMLNode& state ();
XMLNode& get_basic_state (); XMLNode& get_basic_state ();
@ -245,7 +247,7 @@ class LIBARDOUR_API AudioRegion : public Region
protected: protected:
/* default constructor for derived (compound) types */ /* default constructor for derived (compound) types */
AudioRegion (Session& s, samplepos_t, samplecnt_t, std::string name); AudioRegion (Session& s, timecnt_t const &, timecnt_t const &, std::string name);
int _set_state (const XMLNode&, int version, PBD::PropertyChange& what_changed, bool send_signal); int _set_state (const XMLNode&, int version, PBD::PropertyChange& what_changed, bool send_signal);
}; };

View file

@ -27,7 +27,7 @@ namespace ARDOUR {
class Session; class Session;
class LIBARDOUR_API AudioRom : public Readable class LIBARDOUR_API AudioRom : public AudioReadable
{ {
public: public:
static boost::shared_ptr<AudioRom> new_rom (Sample*, size_t); static boost::shared_ptr<AudioRom> new_rom (Sample*, size_t);

View file

@ -41,20 +41,17 @@
namespace ARDOUR { namespace ARDOUR {
class LIBARDOUR_API AudioSource : virtual public Source, class LIBARDOUR_API AudioSource : virtual public Source, public ARDOUR::AudioReadable
public ARDOUR::Readable
{ {
public: public:
AudioSource (Session&, const std::string& name); AudioSource (Session&, const std::string& name);
AudioSource (Session&, const XMLNode&); AudioSource (Session&, const XMLNode&);
virtual ~AudioSource (); virtual ~AudioSource ();
samplecnt_t readable_length() const { return _length; } samplecnt_t readable_length_samples() const { return _length.samples(); }
virtual uint32_t n_channels() const { return 1; } virtual uint32_t n_channels() const { return 1; }
virtual bool empty() const; void update_length (timecnt_t const & cnt);
samplecnt_t length (samplepos_t pos) const;
void update_length (samplecnt_t cnt);
virtual samplecnt_t available_peaks (double zoom) const; virtual samplecnt_t available_peaks (double zoom) const;
@ -107,7 +104,19 @@ class LIBARDOUR_API AudioSource : virtual public Source,
static bool _build_missing_peakfiles; static bool _build_missing_peakfiles;
static bool _build_peakfiles; static bool _build_peakfiles;
samplecnt_t _length; /* these collections of working buffers for supporting
playlist's reading from potentially nested/recursive
sources assume SINGLE THREADED reads by the butler
thread, or a lock around calls that use them.
*/
static std::vector<boost::shared_array<Sample> > _mixdown_buffers;
static std::vector<boost::shared_array<gain_t> > _gain_buffers;
static Glib::Threads::Mutex _level_buffer_lock;
static void ensure_buffers_for_level (uint32_t, samplecnt_t);
static void ensure_buffers_for_level_locked (uint32_t, samplecnt_t);
std::string _peakpath; std::string _peakpath;
int initialize_peakfile (const std::string& path, const bool in_session = false); int initialize_peakfile (const std::string& path, const bool in_session = false);

View file

@ -102,7 +102,7 @@ private:
samplepos_t current_sample; samplepos_t current_sample;
mutable GATOMIC_QUAL gint _auditioning; mutable GATOMIC_QUAL gint _auditioning;
Glib::Threads::Mutex lock; Glib::Threads::Mutex lock;
samplecnt_t length; timecnt_t length;
sampleoffset_t _seek_sample; sampleoffset_t _seek_sample;
bool _seeking; bool _seeking;
bool _seek_complete; bool _seek_complete;
@ -120,7 +120,7 @@ private:
static void*_drop_ports (void*); static void*_drop_ports (void*);
void actually_drop_ports (); void actually_drop_ports ();
void output_changed (IOChange, void*); void output_changed (IOChange, void*);
sampleoffset_t _import_position; timepos_t _import_position;
}; };
}; /* namespace ARDOUR */ }; /* namespace ARDOUR */

View file

@ -85,7 +85,7 @@ public:
boost::shared_ptr<const AutomationControl> automation_control (const Evoral::Parameter& id) const; boost::shared_ptr<const AutomationControl> automation_control (const Evoral::Parameter& id) const;
virtual void add_control(boost::shared_ptr<Evoral::Control>); virtual void add_control(boost::shared_ptr<Evoral::Control>);
virtual bool find_next_event (double start, double end, Evoral::ControlEvent& ev, bool only_active = true) const; virtual bool find_next_event (Temporal::timepos_t const & start, Temporal::timepos_t const & end, Evoral::ControlEvent& ev, bool only_active = true) const;
void clear_controls (); void clear_controls ();
virtual void non_realtime_locate (samplepos_t now); virtual void non_realtime_locate (samplepos_t now);
@ -131,9 +131,8 @@ protected:
SlavableControlList slavables () const { return SlavableControlList(); } SlavableControlList slavables () const { return SlavableControlList(); }
protected: void find_next_ac_event (boost::shared_ptr<AutomationControl>, Temporal::timepos_t const & start, Temporal::timepos_t const & end, Evoral::ControlEvent& ev) const;
void find_next_ac_event (boost::shared_ptr<AutomationControl>, double start, double end, Evoral::ControlEvent& ev) const; void find_prev_ac_event (boost::shared_ptr<AutomationControl>, Temporal::timepos_t const & start, Temporal::timepos_t const & end, Evoral::ControlEvent& ev) const;
void find_prev_ac_event (boost::shared_ptr<AutomationControl>, double start, double end, Evoral::ControlEvent& ev) const;
private: private:
PBD::ScopedConnectionList _control_connections; ///< connections to our controls' signals PBD::ScopedConnectionList _control_connections; ///< connections to our controls' signals

View file

@ -85,8 +85,8 @@ public:
} }
void set_automation_state(AutoState as); void set_automation_state(AutoState as);
void start_touch(double when); void start_touch(timepos_t const & when);
void stop_touch(double when); void stop_touch(timepos_t const & when);
/* inherited from PBD::Controllable. */ /* inherited from PBD::Controllable. */
virtual double get_value () const; virtual double get_value () const;

View file

@ -73,20 +73,21 @@ private:
class LIBARDOUR_API AutomationList : public Evoral::ControlList, public PBD::StatefulDestructible class LIBARDOUR_API AutomationList : public Evoral::ControlList, public PBD::StatefulDestructible
{ {
public: public:
AutomationList (const Evoral::Parameter& id, const Evoral::ParameterDescriptor& desc); AutomationList (const Evoral::Parameter& id, const Evoral::ParameterDescriptor& desc, Temporal::TimeDomain);
AutomationList (const Evoral::Parameter& id); AutomationList (const Evoral::Parameter& id, Temporal::TimeDomain);
AutomationList (const XMLNode&, Evoral::Parameter id); AutomationList (const XMLNode&, Evoral::Parameter id);
AutomationList (const AutomationList&); AutomationList (const AutomationList&);
AutomationList (const AutomationList&, double start, double end); AutomationList (const AutomationList&, timepos_t const & start, timepos_t const & end);
~AutomationList(); ~AutomationList();
virtual boost::shared_ptr<ControlList> create(const Evoral::Parameter& id, virtual boost::shared_ptr<ControlList> create(const Evoral::Parameter& id,
const Evoral::ParameterDescriptor& desc); const Evoral::ParameterDescriptor& desc,
Temporal::TimeDomain);
AutomationList& operator= (const AutomationList&); AutomationList& operator= (const AutomationList&);
void thaw (); void thaw ();
bool paste (const ControlList&, double, BeatsSamplesConverter const&); bool paste (const ControlList&, timepos_t const &, BeatsSamplesConverter const&);
void set_automation_state (AutoState); void set_automation_state (AutoState);
AutoState automation_state() const; AutoState automation_state() const;
@ -103,11 +104,11 @@ public:
static PBD::Signal1<void,AutomationList*> AutomationListCreated; static PBD::Signal1<void,AutomationList*> AutomationListCreated;
void start_write_pass (double when); void start_write_pass (timepos_t const & when);
void write_pass_finished (double when, double thinning_factor=0.0); void write_pass_finished (timepos_t const & when, double thinning_factor=0.0);
void start_touch (double when); void start_touch (timepos_t const & when);
void stop_touch (double when); void stop_touch (timepos_t const & when);
bool touching () const { return g_atomic_int_get (&_touching) != 0; } bool touching () const { return g_atomic_int_get (&_touching) != 0; }
bool writing () const { return _state == Write; } bool writing () const { return _state == Write; }

View file

@ -16,10 +16,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include <cstdlib>
#include "temporal/beats.h" #include "temporal/beats.h"
#include "evoral/TimeConverter.h" #include "temporal/superclock.h"
#include "temporal/time_converter.h"
#include "temporal/types.h"
#include "ardour/libardour_visibility.h" #include "ardour/libardour_visibility.h"
#include "ardour/types.h" #include "ardour/types.h"
@ -27,49 +27,31 @@
#ifndef __ardour_beats_samples_converter_h__ #ifndef __ardour_beats_samples_converter_h__
#define __ardour_beats_samples_converter_h__ #define __ardour_beats_samples_converter_h__
namespace Temporal {
class TempoMap;
}
namespace ARDOUR { namespace ARDOUR {
class TempoMap; /** Converter between quarter-note beats and samplepos_t. Takes distances in
* quarter-note beats or samplepos_t from some origin (supplied to the
/** Converter between quarter-note beats and samples. Takes distances in quarter-note beats or samples * constructor in samplepos_t), and converts them to the opposite unit,
* from some origin (supplied to the constructor in samples), and converts * taking tempo changes into account.
* them to the opposite unit, taking tempo changes into account.
*/ */
class LIBARDOUR_API BeatsSamplesConverter class LIBARDOUR_API BeatsSamplesConverter : public Temporal::TimeConverter<Temporal::Beats,samplepos_t,samplecnt_t> {
: public Evoral::TimeConverter<Temporal::Beats,samplepos_t> {
public: public:
BeatsSamplesConverter (const TempoMap& tempo_map, samplepos_t origin) BeatsSamplesConverter (const Temporal::TempoMap& tempo_map, Temporal::samplepos_t origin)
: Evoral::TimeConverter<Temporal::Beats, samplepos_t> (origin) : Temporal::TimeConverter<Temporal::Beats, samplepos_t, samplecnt_t> (origin)
, _tempo_map(tempo_map) , _tempo_map (tempo_map)
{} {}
samplepos_t to (Temporal::Beats beats) const; samplecnt_t to (Temporal::Beats beats) const;
Temporal::Beats from (samplepos_t samples) const; Temporal::Beats from (samplecnt_t distance) const;
private: private:
const TempoMap& _tempo_map; const Temporal::TempoMap& _tempo_map;
}; };
/** Converter between quarter-note beats and samples. Takes distances in quarter-note beats or samples
* from some origin (supplied to the constructor in samples), and converts
* them to the opposite unit, taking tempo changes into account.
*/
class LIBARDOUR_API DoubleBeatsSamplesConverter
: public Evoral::TimeConverter<double,samplepos_t> {
public:
DoubleBeatsSamplesConverter (const TempoMap& tempo_map, samplepos_t origin)
: Evoral::TimeConverter<double, samplepos_t> (origin)
, _tempo_map(tempo_map)
{}
samplepos_t to (double beats) const;
double from (samplepos_t samples) const;
private:
const TempoMap& _tempo_map;
};
} /* namespace ARDOUR */ } /* namespace ARDOUR */
#endif /* __ardour_beats_samples_converter_h__ */ #endif /* __ardour_beats_samples_converter_h__ */

View file

@ -39,7 +39,7 @@ public:
bool add_impdata ( bool add_impdata (
uint32_t c_in, uint32_t c_in,
uint32_t c_out, uint32_t c_out,
boost::shared_ptr<Readable> r, boost::shared_ptr<AudioReadable> r,
float gain = 1.0, float gain = 1.0,
uint32_t pre_delay = 0, uint32_t pre_delay = 0,
sampleoffset_t offset = 0, sampleoffset_t offset = 0,
@ -64,10 +64,10 @@ protected:
bool _threaded; bool _threaded;
private: private:
class ImpData : public Readable class ImpData : public AudioReadable
{ {
public: public:
ImpData (uint32_t ci, uint32_t co, boost::shared_ptr<Readable> r, float g, float d, sampleoffset_t s = 0, samplecnt_t l = 0, uint32_t c = 0) ImpData (uint32_t ci, uint32_t co, boost::shared_ptr<AudioReadable> r, float g, float d, sampleoffset_t s = 0, samplecnt_t l = 0, uint32_t c = 0)
: c_in (ci) : c_in (ci)
, c_out (co) , c_out (co)
, gain (g) , gain (g)
@ -87,8 +87,8 @@ private:
return _readable->read (s, pos + _offset, cnt, _channel); return _readable->read (s, pos + _offset, cnt, _channel);
} }
samplecnt_t readable_length () const { samplecnt_t readable_length_samples () const {
samplecnt_t rl = _readable->readable_length (); samplecnt_t rl = _readable->readable_length_samples ();
if (rl < _offset) { if (rl < _offset) {
return 0; return 0;
} else if (_length > 0) { } else if (_length > 0) {
@ -103,7 +103,7 @@ private:
} }
private: private:
boost::shared_ptr<Readable> _readable; boost::shared_ptr<AudioReadable> _readable;
sampleoffset_t _offset; sampleoffset_t _offset;
samplecnt_t _length; samplecnt_t _length;
@ -172,7 +172,7 @@ public:
void run_stereo_no_latency (float* L, float* R, uint32_t); void run_stereo_no_latency (float* L, float* R, uint32_t);
private: private:
std::vector<boost::shared_ptr<Readable> > _readables; std::vector<boost::shared_ptr<AudioReadable> > _readables;
IRChannelConfig _irc; IRChannelConfig _irc;
IRSettings _ir_settings; IRSettings _ir_settings;

View file

@ -181,13 +181,13 @@ protected:
virtual void playlist_changed (const PBD::PropertyChange&) {} virtual void playlist_changed (const PBD::PropertyChange&) {}
virtual void playlist_deleted (boost::weak_ptr<Playlist>); virtual void playlist_deleted (boost::weak_ptr<Playlist>);
virtual void playlist_ranges_moved (std::list< Evoral::RangeMove<samplepos_t> > const &, bool) {} virtual void playlist_ranges_moved (std::list<Temporal::RangeMove> const &, bool) {}
/* The MIDI stuff */ /* The MIDI stuff */
MidiRingBuffer<samplepos_t>* _midi_buf; MidiRingBuffer<samplepos_t>* _midi_buf;
static void get_location_times (const Location* location, samplepos_t* start, samplepos_t* end, samplepos_t* length); static void get_location_times (const Location* location, timepos_t* start, timepos_t* end, timecnt_t* length);
}; };
} // namespace ARDOUR } // namespace ARDOUR

View file

@ -73,7 +73,7 @@ public:
float buffer_load () const; float buffer_load () const;
void move_processor_automation (boost::weak_ptr<Processor>, std::list<Evoral::RangeMove<samplepos_t> > const&); void move_processor_automation (boost::weak_ptr<Processor>, std::list<Temporal::RangeMove> const&);
/* called by the Butler in a non-realtime context as part of its normal /* called by the Butler in a non-realtime context as part of its normal
* buffer refill loop (not due to transport-mechanism requests like * buffer refill loop (not due to transport-mechanism requests like
@ -151,7 +151,7 @@ protected:
void resolve_tracker (Evoral::EventSink<samplepos_t>& buffer, samplepos_t time); void resolve_tracker (Evoral::EventSink<samplepos_t>& buffer, samplepos_t time);
int use_playlist (DataType, boost::shared_ptr<Playlist>); int use_playlist (DataType, boost::shared_ptr<Playlist>);
void playlist_ranges_moved (std::list<Evoral::RangeMove<samplepos_t> > const&, bool); void playlist_ranges_moved (std::list<Temporal::RangeMove> const&, bool);
int add_channel_to (boost::shared_ptr<ChannelList>, uint32_t how_many); int add_channel_to (boost::shared_ptr<ChannelList>, uint32_t how_many);

View file

@ -157,7 +157,7 @@ private:
bool prep_record_enable (); bool prep_record_enable ();
bool prep_record_disable (); bool prep_record_disable ();
void calculate_record_range (Evoral::OverlapType ot, samplepos_t transport_sample, void calculate_record_range (Temporal::OverlapType ot, samplepos_t transport_sample,
samplecnt_t nframes, samplecnt_t& rec_nframes, samplecnt_t nframes, samplecnt_t& rec_nframes,
samplecnt_t& rec_offset); samplecnt_t& rec_offset);

View file

@ -33,7 +33,7 @@ public:
EBUr128Analysis (float sample_rate); EBUr128Analysis (float sample_rate);
~EBUr128Analysis(); ~EBUr128Analysis();
int run (Readable*); int run (AudioReadable*);
float loudness () const { return _loudness; } float loudness () const { return _loudness; }
float loudness_range () const { return _loudness_range; } float loudness_range () const { return _loudness_range; }

View file

@ -125,8 +125,8 @@ class LIBARDOUR_API RegionExportChannelFactory
size_t n_channels; size_t n_channels;
BufferSet buffers; BufferSet buffers;
bool buffers_up_to_date; bool buffers_up_to_date;
samplecnt_t region_start; samplepos_t region_start;
samplecnt_t position; samplepos_t position;
boost::scoped_array<Sample> mixdown_buffer; boost::scoped_array<Sample> mixdown_buffer;
boost::scoped_array<Sample> gain_buffer; boost::scoped_array<Sample> gain_buffer;

View file

@ -65,7 +65,7 @@ public:
}; };
Location (Session &); Location (Session &);
Location (Session &, samplepos_t, samplepos_t, const std::string &, Flags bits = Flags(0), const uint32_t sub_num = 0); Location (Session &, Temporal::timepos_t const &, Temporal::timepos_t const &, const std::string &, Flags bits = Flags(0));
Location (const Location& other); Location (const Location& other);
Location (Session &, const XMLNode&); Location (Session &, const XMLNode&);
Location* operator= (const Location& other); Location* operator= (const Location& other);
@ -77,15 +77,19 @@ public:
void unlock (); void unlock ();
int64_t timestamp() const { return _timestamp; }; int64_t timestamp() const { return _timestamp; };
samplepos_t start() const { return _start; } timepos_t start() const { return _start; }
samplepos_t end() const { return _end; } timepos_t end() const { return _end; }
samplecnt_t length() const { return _end - _start; } timecnt_t length() const { return _start.distance (_end); }
int set_start (samplepos_t s, bool force = false, bool allow_beat_recompute = true, const uint32_t sub_num = 0); samplepos_t start_sample() const { return _start.samples(); }
int set_end (samplepos_t e, bool force = false, bool allow_beat_recompute = true, const uint32_t sub_num = 0); samplepos_t end_sample() const { return _end.samples(); }
int set (samplepos_t start, samplepos_t end, bool allow_beat_recompute = true, const uint32_t sub_num = 0); samplecnt_t length_samples() const { return _end.samples() - _start.samples(); }
int move_to (samplepos_t pos, const uint32_t sub_num); int set_start (timepos_t const & s, bool force = false);
int set_end (timepos_t const & e, bool force = false);
int set (timepos_t const & start, timepos_t const & end);
int move_to (timepos_t const & pos);
const std::string& name() const { return _name; } const std::string& name() const { return _name; }
void set_name (const std::string &str); void set_name (const std::string &str);
@ -126,7 +130,7 @@ public:
static PBD::Signal1<void,Location*> start_changed; static PBD::Signal1<void,Location*> start_changed;
static PBD::Signal1<void,Location*> flags_changed; static PBD::Signal1<void,Location*> flags_changed;
static PBD::Signal1<void,Location*> lock_changed; static PBD::Signal1<void,Location*> lock_changed;
static PBD::Signal1<void,Location*> position_lock_style_changed; static PBD::Signal1<void,Location*> position_time_domain_changed;
/* this is sent only when both start and end change at the same time */ /* this is sent only when both start and end change at the same time */
static PBD::Signal1<void,Location*> changed; static PBD::Signal1<void,Location*> changed;
@ -142,7 +146,7 @@ public:
PBD::Signal0<void> StartChanged; PBD::Signal0<void> StartChanged;
PBD::Signal0<void> FlagsChanged; PBD::Signal0<void> FlagsChanged;
PBD::Signal0<void> LockChanged; PBD::Signal0<void> LockChanged;
PBD::Signal0<void> PositionLockStyleChanged; PBD::Signal0<void> TimeDomainChanged;
/* CD Track / CD-Text info */ /* CD Track / CD-Text info */
@ -152,28 +156,23 @@ public:
XMLNode& get_state (void); XMLNode& get_state (void);
int set_state (const XMLNode&, int version); int set_state (const XMLNode&, int version);
PositionLockStyle position_lock_style() const { return _position_lock_style; } Temporal::TimeDomain position_time_domain() const { return _start.time_domain(); }
void set_position_lock_style (PositionLockStyle ps); void set_position_time_domain (Temporal::TimeDomain ps);
void recompute_samples_from_beat ();
static PBD::Signal0<void> scene_changed; /* for use by backend scene change management, class level */ static PBD::Signal0<void> scene_changed; /* for use by backend scene change management, class level */
PBD::Signal0<void> SceneChangeChanged; /* for use by objects interested in this object */ PBD::Signal0<void> SceneChangeChanged; /* for use by objects interested in this object */
private: private:
std::string _name; std::string _name;
samplepos_t _start; timepos_t _start;
double _start_beat; timepos_t _end;
samplepos_t _end;
double _end_beat;
Flags _flags; Flags _flags;
bool _locked; bool _locked;
PositionLockStyle _position_lock_style;
boost::shared_ptr<SceneChange> _scene_change; boost::shared_ptr<SceneChange> _scene_change;
int64_t _timestamp; int64_t _timestamp;
void set_mark (bool yn); void set_mark (bool yn);
bool set_flag_internal (bool yn, Flags flag); bool set_flag_internal (bool yn, Flags flag);
void recompute_beat_from_samples (const uint32_t sub_num);
}; };
/** A collection of session locations including unique dedicated locations (loop, punch, etc) */ /** A collection of session locations including unique dedicated locations (loop, punch, etc) */
@ -229,7 +228,7 @@ public:
samplepos_t first_mark_before (samplepos_t, bool include_special_ranges = false); samplepos_t first_mark_before (samplepos_t, bool include_special_ranges = false);
samplepos_t first_mark_after (samplepos_t, bool include_special_ranges = false); samplepos_t first_mark_after (samplepos_t, bool include_special_ranges = false);
void marks_either_side (samplepos_t const, samplepos_t &, samplepos_t &) const; void marks_either_side (timepos_t const &, timepos_t &, timepos_t &) const;
/** Return range with closest start pos to the where argument /** Return range with closest start pos to the where argument
* *
@ -239,9 +238,9 @@ public:
* *
* @return Location object or nil * @return Location object or nil
*/ */
Location* range_starts_at(samplepos_t pos, samplecnt_t slop = 0, bool incl = false) const; Location* range_starts_at(samplepos_t, samplecnt_t slop = 0, bool incl = false) const;
void find_all_between (samplepos_t start, samplepos_t, LocationList&, Location::Flags); void find_all_between (timepos_t const & start, timepos_t const & end, LocationList&, Location::Flags);
PBD::Signal1<void,Location*> current_changed; PBD::Signal1<void,Location*> current_changed;

View file

@ -36,7 +36,7 @@
#include "ardour/session.h" #include "ardour/session.h"
namespace ARDOUR { namespace ARDOUR {
class Readable; class AudioReadable;
} }
namespace ARDOUR { namespace LuaAPI { namespace ARDOUR { namespace LuaAPI {
@ -269,7 +269,7 @@ namespace ARDOUR { namespace LuaAPI {
* *
* This interface allows to load a plugins and directly access it using the Vamp Plugin API. * This interface allows to load a plugins and directly access it using the Vamp Plugin API.
* *
* A convenience method is provided to analyze Ardour::Readable objects (Regions). * A convenience method is provided to analyze Ardour::AudioReadable objects (Regions).
*/ */
public: public:
Vamp (const std::string&, float sample_rate); Vamp (const std::string&, float sample_rate);
@ -282,7 +282,7 @@ namespace ARDOUR { namespace LuaAPI {
::Vamp::Plugin* plugin () { return _plugin; } ::Vamp::Plugin* plugin () { return _plugin; }
/** high-level abstraction to process a single channel of the given Readable. /** high-level abstraction to process a single channel of the given AudioReadable.
* *
* If the plugin is not yet initialized, initialize() is called. * If the plugin is not yet initialized, initialize() is called.
* *
@ -294,7 +294,7 @@ namespace ARDOUR { namespace LuaAPI {
* @param fn lua callback function or nil * @param fn lua callback function or nil
* @return 0 on success * @return 0 on success
*/ */
int analyze (boost::shared_ptr<ARDOUR::Readable> r, uint32_t channel, luabridge::LuaRef fn); int analyze (boost::shared_ptr<ARDOUR::AudioReadable> r, uint32_t channel, luabridge::LuaRef fn);
/** call plugin():reset() and clear intialization flag */ /** call plugin():reset() and clear intialization flag */
void reset (); void reset ();
@ -341,7 +341,7 @@ namespace ARDOUR { namespace LuaAPI {
}; };
class Rubberband : public Readable , public boost::enable_shared_from_this<Rubberband> class Rubberband : public AudioReadable , public boost::enable_shared_from_this<Rubberband>
{ {
public: public:
Rubberband (boost::shared_ptr<AudioRegion>, bool percussive); Rubberband (boost::shared_ptr<AudioRegion>, bool percussive);
@ -349,10 +349,10 @@ namespace ARDOUR { namespace LuaAPI {
bool set_strech_and_pitch (double stretch_ratio, double pitch_ratio); bool set_strech_and_pitch (double stretch_ratio, double pitch_ratio);
bool set_mapping (luabridge::LuaRef tbl); bool set_mapping (luabridge::LuaRef tbl);
boost::shared_ptr<AudioRegion> process (luabridge::LuaRef cb); boost::shared_ptr<AudioRegion> process (luabridge::LuaRef cb);
boost::shared_ptr<Readable> readable (); boost::shared_ptr<AudioReadable> readable ();
/* readable API */ /* audioreadable API */
samplecnt_t readable_length () const { return _read_len; } samplecnt_t readable_length_samples () const { return _read_len; }
uint32_t n_channels () const { return _n_channels; } uint32_t n_channels () const { return _n_channels; }
samplecnt_t read (Sample*, samplepos_t pos, samplecnt_t cnt, int channel) const; samplecnt_t read (Sample*, samplepos_t pos, samplecnt_t cnt, int channel) const;

View file

@ -35,7 +35,7 @@
namespace ARDOUR { namespace ARDOUR {
struct MidiCursor : public boost::noncopyable { struct MidiCursor : public boost::noncopyable {
MidiCursor() : last_read_end(0) {} MidiCursor() {}
void connect(PBD::Signal1<void, bool>& invalidated) { void connect(PBD::Signal1<void, bool>& invalidated) {
connections.drop_connections(); connections.drop_connections();
@ -50,7 +50,7 @@ struct MidiCursor : public boost::noncopyable {
Evoral::Sequence<Temporal::Beats>::const_iterator iter; Evoral::Sequence<Temporal::Beats>::const_iterator iter;
std::set<Evoral::Sequence<Temporal::Beats>::WeakNotePtr> active_notes; std::set<Evoral::Sequence<Temporal::Beats>::WeakNotePtr> active_notes;
samplepos_t last_read_end; timepos_t last_read_end;
PBD::ScopedConnectionList connections; PBD::ScopedConnectionList connections;
}; };

View file

@ -300,7 +300,7 @@ public:
int set_state(const XMLNode&) { return 0; } int set_state(const XMLNode&) { return 0; }
PBD::Signal0<void> ContentsChanged; PBD::Signal0<void> ContentsChanged;
PBD::Signal1<void, double> ContentsShifted; PBD::Signal1<void, Temporal::timecnt_t> ContentsShifted;
boost::shared_ptr<const MidiSource> midi_source (); boost::shared_ptr<const MidiSource> midi_source ();
void set_midi_source (boost::shared_ptr<MidiSource>); void set_midi_source (boost::shared_ptr<MidiSource>);

View file

@ -64,8 +64,8 @@ public:
/** This constructor does NOT notify others (session) */ /** This constructor does NOT notify others (session) */
MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other,
samplepos_t start, timepos_t const & start,
samplecnt_t cnt, timepos_t const & cnt,
std::string name, std::string name,
bool hidden = false); bool hidden = false);
@ -77,7 +77,8 @@ public:
int set_state (const XMLNode&, int version); int set_state (const XMLNode&, int version);
bool destroy_region (boost::shared_ptr<Region>); bool destroy_region (boost::shared_ptr<Region>);
void _split_region (boost::shared_ptr<Region>, const MusicSample& position, ThawList& thawlist);
void _split_region (boost::shared_ptr<Region>, timepos_t const & position, Thawlist& thawlist);
void set_note_mode (NoteMode m) { _note_mode = m; } void set_note_mode (NoteMode m) { _note_mode = m; }

View file

@ -1,84 +0,0 @@
/*
* Copyright (C) 2011-2015 David Robillard <d@drobilla.net>
* Copyright (C) 2011-2017 Paul Davis <paul@linuxaudiosystems.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __ardour_midi_playlist_source_h__
#define __ardour_midi_playlist_source_h__
#include <string>
#include <boost/shared_ptr.hpp>
#include "ardour/ardour.h"
#include "ardour/midi_source.h"
#include "ardour/playlist_source.h"
namespace ARDOUR {
class MidiPlaylist;
class LIBARDOUR_API MidiPlaylistSource : public MidiSource, public PlaylistSource {
public:
virtual ~MidiPlaylistSource ();
bool empty() const;
samplecnt_t length (samplepos_t) const;
samplecnt_t read_unlocked (Sample *dst, samplepos_t start, samplecnt_t cnt) const;
samplecnt_t write_unlocked (Sample *src, samplecnt_t cnt);
XMLNode& get_state ();
int set_state (const XMLNode&, int version);
void append_event_beats(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<Temporal::Beats>& ev);
void append_event_samples(const Glib::Threads::Mutex::Lock& lock, const Evoral::Event<samplepos_t>& ev, samplepos_t source_start);
void load_model(const Glib::Threads::Mutex::Lock& lock, bool force_reload=false);
void destroy_model(const Glib::Threads::Mutex::Lock& lock);
protected:
friend class SourceFactory;
MidiPlaylistSource (Session&, const PBD::ID& orig, const std::string& name, boost::shared_ptr<MidiPlaylist>, uint32_t chn,
sampleoffset_t begin, samplecnt_t len, Source::Flag flags);
MidiPlaylistSource (Session&, const XMLNode&);
void flush_midi(const Lock& lock);
samplecnt_t read_unlocked (const Lock& lock,
Evoral::EventSink<samplepos_t>& dst,
samplepos_t position,
samplepos_t start,
samplecnt_t cnt,
Evoral::Range<samplepos_t>* loop_range,
MidiStateTracker* tracker,
MidiChannelFilter* filter) const;
samplecnt_t write_unlocked (const Lock& lock,
MidiRingBuffer<samplepos_t>& dst,
samplepos_t position,
samplecnt_t cnt);
private:
int set_state (const XMLNode&, int version, bool with_descendants);
samplecnt_t _length;
};
} /* namespace */
#endif /* __ardour_midi_playlist_source_h__ */

View file

@ -26,7 +26,7 @@
#include <vector> #include <vector>
#include "temporal/beats.h" #include "temporal/beats.h"
#include "evoral/Range.h" #include "temporal/range.h"
#include "pbd/string_convert.h" #include "pbd/string_convert.h"
@ -68,26 +68,23 @@ class LIBARDOUR_API MidiRegion : public Region
boost::shared_ptr<MidiSource> midi_source (uint32_t n=0) const; boost::shared_ptr<MidiSource> midi_source (uint32_t n=0) const;
/* Stub Readable interface */ timecnt_t read_at (Evoral::EventSink<samplepos_t>& dst,
virtual samplecnt_t read (Sample*, samplepos_t /*pos*/, samplecnt_t /*cnt*/, int /*channel*/) const { return 0; } timepos_t const & position,
timecnt_t const & dur,
Temporal::Range* loop_range,
MidiCursor& cursor,
uint32_t chan_n = 0,
NoteMode mode = Sustained,
MidiStateTracker* tracker = 0,
MidiChannelFilter* filter = 0) const;
samplecnt_t read_at (Evoral::EventSink<samplepos_t>& dst, timecnt_t master_read_at (MidiRingBuffer<samplepos_t>& dst,
samplepos_t position, timepos_t const & position,
samplecnt_t dur, timecnt_t const & dur,
Evoral::Range<samplepos_t>* loop_range, Temporal::Range* loop_range,
MidiCursor& cursor, MidiCursor& cursor,
uint32_t chan_n = 0, uint32_t chan_n = 0,
NoteMode mode = Sustained, NoteMode mode = Sustained) const;
MidiStateTracker* tracker = 0,
MidiChannelFilter* filter = 0) const;
samplecnt_t master_read_at (MidiRingBuffer<samplepos_t>& dst,
samplepos_t position,
samplecnt_t dur,
Evoral::Range<samplepos_t>* loop_range,
MidiCursor& cursor,
uint32_t chan_n = 0,
NoteMode mode = Sustained) const;
XMLNode& state (); XMLNode& state ();
int set_state (const XMLNode&, int version); int set_state (const XMLNode&, int version);
@ -127,38 +124,30 @@ class LIBARDOUR_API MidiRegion : public Region
MidiRegion (boost::shared_ptr<const MidiRegion>); MidiRegion (boost::shared_ptr<const MidiRegion>);
MidiRegion (boost::shared_ptr<const MidiRegion>, timecnt_t const & offset); MidiRegion (boost::shared_ptr<const MidiRegion>, timecnt_t const & offset);
samplecnt_t _read_at (const SourceList&, Evoral::EventSink<samplepos_t>& dst, timecnt_t _read_at (const SourceList&, Evoral::EventSink<samplepos_t>& dst,
samplepos_t position, timepos_t const & position,
samplecnt_t dur, timecnt_t const & dur,
Evoral::Range<samplepos_t>* loop_range, Temporal::Range* loop_range,
MidiCursor& cursor, MidiCursor& cursor,
uint32_t chan_n = 0, uint32_t chan_n = 0,
NoteMode mode = Sustained, NoteMode mode = Sustained,
MidiStateTracker* tracker = 0, MidiStateTracker* tracker = 0,
MidiChannelFilter* filter = 0) const; MidiChannelFilter* filter = 0) const;
void register_properties (); void register_properties ();
void post_set (const PBD::PropertyChange&);
void recompute_at_start (); void recompute_at_start ();
void recompute_at_end (); void recompute_at_end ();
bool set_name (const std::string & str); bool set_name (const std::string & str);
void set_position_internal (timepos_t const & pos);
void set_length_internal (timecnt_t const & len);
void set_start_internal (timecnt_t const &); void set_start_internal (timecnt_t const &);
void trim_to_internal (timepos_t const & position, timecnt_t const & length);
void update_length_beats ();
void model_changed (); void model_changed ();
void model_contents_changed (); void model_contents_changed ();
void model_shifted (double qn_distance); void model_shifted (timecnt_t qn_distance);
void model_automation_state_changed (Evoral::Parameter const &); void model_automation_state_changed (Evoral::Parameter const &);
void set_start_beats_from_start_samples ();
void update_after_tempo_map_change (bool send_change = true);
std::set<Evoral::Parameter> _filtered_parameters; ///< parameters that we ask our source not to return when reading std::set<Evoral::Parameter> _filtered_parameters; ///< parameters that we ask our source not to return when reading
PBD::ScopedConnection _model_connection; PBD::ScopedConnection _model_connection;
PBD::ScopedConnection _model_shift_connection; PBD::ScopedConnection _model_shift_connection;

View file

@ -27,10 +27,14 @@
#include <time.h> #include <time.h>
#include <glibmm/threads.h> #include <glibmm/threads.h>
#include <boost/enable_shared_from_this.hpp> #include <boost/enable_shared_from_this.hpp>
#include "pbd/stateful.h" #include "pbd/stateful.h"
#include "pbd/xml++.h" #include "pbd/xml++.h"
#include "evoral/Sequence.h" #include "evoral/Sequence.h"
#include "evoral/Range.h"
#include "temporal/range.h"
#include "ardour/ardour.h" #include "ardour/ardour.h"
#include "ardour/buffer.h" #include "ardour/buffer.h"
#include "ardour/midi_cursor.h" #include "ardour/midi_cursor.h"
@ -95,21 +99,17 @@ class LIBARDOUR_API MidiSource : virtual public Source
* @param filter Channel filter to apply or NULL to disable filter * @param filter Channel filter to apply or NULL to disable filter
* @param tracker an optional pointer to MidiStateTracker object, for note on/off tracking. * @param tracker an optional pointer to MidiStateTracker object, for note on/off tracking.
* @param filtered Parameters whose MIDI messages will not be returned. * @param filtered Parameters whose MIDI messages will not be returned.
* @param pos_beats Start position (quarter note = \p pos_beats - \p start_beats)
* @param start_beats Start position offset
*/ */
virtual samplecnt_t midi_read (const Lock& lock, virtual timecnt_t midi_read (const Lock& lock,
Evoral::EventSink<samplepos_t>& dst, Evoral::EventSink<samplepos_t>& dst,
samplepos_t source_start, timepos_t const & source_start,
samplepos_t start, timecnt_t const & start,
samplecnt_t cnt, timecnt_t const & cnt,
Evoral::Range<samplepos_t>* loop_range, Temporal::Range* loop_range,
MidiCursor& cursor, MidiCursor& cursor,
MidiStateTracker* tracker, MidiStateTracker* tracker,
MidiChannelFilter* filter, MidiChannelFilter* filter,
const std::set<Evoral::Parameter>& filtered, const std::set<Evoral::Parameter>& filtered);
const double pos_beats,
const double start_beats) const;
/** Write data from a MidiRingBuffer to this source. /** Write data from a MidiRingBuffer to this source.
* @param lock Reference to the Mutex to lock before modification * @param lock Reference to the Mutex to lock before modification
@ -117,10 +117,10 @@ class LIBARDOUR_API MidiSource : virtual public Source
* @param source_start This source's start position in session samples. * @param source_start This source's start position in session samples.
* @param cnt The length of time to write. * @param cnt The length of time to write.
*/ */
virtual samplecnt_t midi_write (const Lock& lock, virtual timecnt_t midi_write (const Lock& lock,
MidiRingBuffer<samplepos_t>& source, MidiRingBuffer<samplepos_t>& source,
samplepos_t source_start, timepos_t const & source_start,
samplecnt_t cnt); timecnt_t const & cnt);
/** Append a single event with a timestamp in beats. /** Append a single event with a timestamp in beats.
* *
@ -137,10 +137,6 @@ class LIBARDOUR_API MidiSource : virtual public Source
const Evoral::Event<samplepos_t>& ev, const Evoral::Event<samplepos_t>& ev,
samplepos_t source_start) = 0; samplepos_t source_start) = 0;
virtual bool empty () const;
virtual samplecnt_t length (samplepos_t pos) const;
virtual void update_length (samplecnt_t);
virtual void mark_streaming_midi_write_started (const Lock& lock, NoteMode mode); virtual void mark_streaming_midi_write_started (const Lock& lock, NoteMode mode);
virtual void mark_streaming_write_started (const Lock& lock); virtual void mark_streaming_write_started (const Lock& lock);
virtual void mark_streaming_write_completed (const Lock& lock); virtual void mark_streaming_write_completed (const Lock& lock);
@ -216,14 +212,14 @@ class LIBARDOUR_API MidiSource : virtual public Source
protected: protected:
virtual void flush_midi(const Lock& lock) = 0; virtual void flush_midi(const Lock& lock) = 0;
virtual samplecnt_t read_unlocked (const Lock& lock, virtual timecnt_t read_unlocked (const Lock& lock,
Evoral::EventSink<samplepos_t>& dst, Evoral::EventSink<samplepos_t>& dst,
samplepos_t position, timepos_t const & position,
samplepos_t start, timecnt_t const & start,
samplecnt_t cnt, timecnt_t const & cnt,
Evoral::Range<samplepos_t>* loop_range, Temporal::Range* loop_range,
MidiStateTracker* tracker, MidiStateTracker* tracker,
MidiChannelFilter* filter) const = 0; MidiChannelFilter* filter) const = 0;
/** Write data to this source from a MidiRingBuffer. /** Write data to this source from a MidiRingBuffer.
* @param lock Reference to the Mutex to lock before modification * @param lock Reference to the Mutex to lock before modification
@ -231,10 +227,10 @@ class LIBARDOUR_API MidiSource : virtual public Source
* @param position This source's start position in session samples. * @param position This source's start position in session samples.
* @param cnt The duration of this block to write for. * @param cnt The duration of this block to write for.
*/ */
virtual samplecnt_t write_unlocked (const Lock& lock, virtual timecnt_t write_unlocked (const Lock& lock,
MidiRingBuffer<samplepos_t>& source, MidiRingBuffer<samplepos_t>& source,
samplepos_t position, timepos_t const & position,
samplecnt_t cnt) = 0; timecnt_t const & cnt) = 0;
boost::shared_ptr<MidiModel> _model; boost::shared_ptr<MidiModel> _model;
bool _writing; bool _writing;

View file

@ -40,7 +40,7 @@ public:
void set_minioi (float); void set_minioi (float);
void set_function (int); void set_function (int);
int run (const std::string& path, Readable*, uint32_t channel, AnalysisFeatureList& results); int run (const std::string& path, AudioReadable*, uint32_t channel, AnalysisFeatureList& results);
static void cleanup_onsets (AnalysisFeatureList&, float sr, float gap_msecs); static void cleanup_onsets (AnalysisFeatureList&, float sr, float gap_msecs);

View file

@ -37,11 +37,12 @@ class Pannable;
class LIBARDOUR_API PanControllable : public AutomationControl class LIBARDOUR_API PanControllable : public AutomationControl
{ {
public: public:
#warning NUTEMPO QUESTION what time domain shoudl this really use?
PanControllable (Session& s, std::string name, Pannable* o, Evoral::Parameter param) PanControllable (Session& s, std::string name, Pannable* o, Evoral::Parameter param)
: AutomationControl (s, : AutomationControl (s,
param, param,
ParameterDescriptor(param), ParameterDescriptor(param),
boost::shared_ptr<AutomationList>(new AutomationList(param)), boost::shared_ptr<AutomationList>(new AutomationList(param, Temporal::AudioTime)),
name) name)
, owner (o) , owner (o)
{} {}

View file

@ -64,9 +64,11 @@ public:
return ((_auto_state & Write) || ((_auto_state & (Touch | Latch)) && touching())); return ((_auto_state & Write) || ((_auto_state & (Touch | Latch)) && touching()));
} }
void start_touch (double when); void start_touch (timepos_t const & when);
void stop_touch (double when); void stop_touch (timepos_t const & when);
bool touching() const { return g_atomic_int_get (&_touching); } bool touching() const { return g_atomic_int_get (&_touching); }
bool writing() const { return _auto_state == Write; } bool writing() const { return _auto_state == Write; }
bool touch_enabled() const { return _auto_state & (Touch | Latch); } bool touch_enabled() const { return _auto_state & (Touch | Latch); }

View file

@ -46,7 +46,7 @@
#include "pbd/undo.h" #include "pbd/undo.h"
#include "pbd/g_atomic_compat.h" #include "pbd/g_atomic_compat.h"
#include "evoral/Range.h" #include "temporal/range.h"
#include "ardour/ardour.h" #include "ardour/ardour.h"
#include "ardour/data_type.h" #include "ardour/data_type.h"
@ -95,7 +95,7 @@ public:
Playlist (Session&, const XMLNode&, DataType type, bool hidden = false); Playlist (Session&, const XMLNode&, DataType type, bool hidden = false);
Playlist (Session&, std::string name, DataType type, bool hidden = false); Playlist (Session&, std::string name, DataType type, bool hidden = false);
Playlist (boost::shared_ptr<const Playlist>, std::string name, bool hidden = false); Playlist (boost::shared_ptr<const Playlist>, std::string name, bool hidden = false);
Playlist (boost::shared_ptr<const Playlist>, samplepos_t start, samplecnt_t cnt, std::string name, bool hidden = false); Playlist (boost::shared_ptr<const Playlist>, timepos_t const & start, timepos_t const & cnt, std::string name, bool hidden = false);
virtual ~Playlist (); virtual ~Playlist ();
@ -159,51 +159,54 @@ public:
bool shared_with (const PBD::ID&) const; bool shared_with (const PBD::ID&) const;
void reset_shares (); void reset_shares ();
uint32_t n_regions () const; uint32_t n_regions() const;
bool all_regions_empty () const; bool all_regions_empty() const;
std::pair<samplepos_t, samplepos_t> get_extent () const; std::pair<timepos_t, timepos_t> get_extent () const;
std::pair<samplepos_t, samplepos_t> get_extent_with_endspace () const; std::pair<timepos_t, timepos_t> get_extent_with_endspace() const;
layer_t top_layer () const; layer_t top_layer() const;
EditMode get_edit_mode() const { return _edit_mode; }
void set_edit_mode (EditMode);
/* Editing operations */ /* Editing operations */
void add_region (boost::shared_ptr<Region>, samplepos_t position, float times = 1, bool auto_partition = false, int32_t sub_num = 0, double quarter_note = 0.0, bool for_music = false); void add_region (boost::shared_ptr<Region>, timepos_t const & position, float times = 1, bool auto_partition = false);
void remove_region (boost::shared_ptr<Region>); void remove_region (boost::shared_ptr<Region>);
void get_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&); void get_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
void replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, samplepos_t pos);
void split_region (boost::shared_ptr<Region>, const MusicSample& position);
void split (const MusicSample& at);
void shift (samplepos_t at, sampleoffset_t distance, bool move_intersected, bool ignore_music_glue);
void partition (samplepos_t start, samplepos_t end, bool cut = false);
void duplicate (boost::shared_ptr<Region>, samplepos_t position, float times);
void duplicate (boost::shared_ptr<Region>, samplepos_t position, samplecnt_t gap, float times);
void duplicate_until (boost::shared_ptr<Region>, samplepos_t position, samplecnt_t gap, samplepos_t end);
void duplicate_range (AudioRange&, float times);
void duplicate_ranges (std::list<AudioRange>&, float times);
void nudge_after (samplepos_t start, samplecnt_t distance, bool forwards);
void fade_range (std::list<AudioRange>&);
void remove_gaps (samplepos_t gap_threshold, samplepos_t leave_gap, boost::function<void (samplepos_t, samplecnt_t)> gap_callback);
void get_region_list_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
void get_source_equivalent_regions (boost::shared_ptr<Region>, std::vector<boost::shared_ptr<Region> >&);
void replace_region (boost::shared_ptr<Region> old, boost::shared_ptr<Region> newr, timepos_t const & pos);
void split_region (boost::shared_ptr<Region>, timepos_t const & position);
void split (timepos_t const & at);
void shift (timepos_t const & at, timecnt_t const & distance, bool move_intersected, bool ignore_music_glue);
void partition (timepos_t const & start, timepos_t const & end, bool cut = false);
void duplicate (boost::shared_ptr<Region>, timepos_t & position, float times);
void duplicate (boost::shared_ptr<Region>, timepos_t & position, timecnt_t const & gap, float times);
void duplicate_until (boost::shared_ptr<Region>, timepos_t & position, timecnt_t const & gap, timepos_t const & end);
void duplicate_range (TimelineRange&, float times);
void duplicate_ranges (std::list<TimelineRange>&, float times);
void nudge_after (timepos_t const & start, timecnt_t const & distance, bool forwards);
boost::shared_ptr<Region> combine (const RegionList&); boost::shared_ptr<Region> combine (const RegionList&);
void uncombine (boost::shared_ptr<Region>); void uncombine (boost::shared_ptr<Region>);
void fade_range (std::list<TimelineRange>&);
void shuffle (boost::shared_ptr<Region>, int dir); void shuffle (boost::shared_ptr<Region>, int dir);
void ripple (samplepos_t at, samplecnt_t distance, RegionList* exclude); void ripple (timepos_t const & at, timecnt_t const & distance, RegionList *exclude);
void ripple (samplepos_t at, samplecnt_t distance, boost::shared_ptr<Region> exclude) void ripple (timepos_t const & at, timecnt_t const & distance, boost::shared_ptr<Region> exclude) {
{ RegionList el;
RegionList el; if (exclude) {
if (exclude) { el.push_back (exclude);
el.push_back (exclude); }
} ripple (at, distance, &el);
ripple (at, distance, &el);
} }
void update_after_tempo_map_change (); void update_after_tempo_map_change ();
boost::shared_ptr<Playlist> cut (std::list<AudioRange>&, bool result_is_hidden = true); boost::shared_ptr<Playlist> cut (std::list<TimelineRange>&, bool result_is_hidden = true);
boost::shared_ptr<Playlist> copy (std::list<AudioRange>&, bool result_is_hidden = true); boost::shared_ptr<Playlist> copy (std::list<TimelineRange>&, bool result_is_hidden = true);
int paste (boost::shared_ptr<Playlist>, samplepos_t position, float times, const int32_t sub_num); int paste (boost::shared_ptr<Playlist>, timepos_t const & position, float times);
const RegionListProperty& region_list_property () const const RegionListProperty& region_list_property () const
{ {
@ -212,31 +215,31 @@ public:
boost::shared_ptr<RegionList> region_list (); boost::shared_ptr<RegionList> region_list ();
boost::shared_ptr<RegionList> regions_at (samplepos_t sample); boost::shared_ptr<RegionList> regions_at (timepos_t const & sample);
uint32_t count_regions_at (samplepos_t) const; uint32_t count_regions_at (timepos_t const &) const;
/** @param start Range start. /** @param start Range start.
* @param end Range end. * @param end Range end.
* @return regions which have some part within this range. * @return regions which have some part within this range.
*/ */
boost::shared_ptr<RegionList> regions_touched (samplepos_t start, samplepos_t end); boost::shared_ptr<RegionList> regions_touched (timepos_t const & start, timepos_t const & end);
boost::shared_ptr<RegionList> regions_with_start_within (Evoral::Range<samplepos_t>); boost::shared_ptr<RegionList> regions_with_start_within (Temporal::TimeRange);
boost::shared_ptr<RegionList> regions_with_end_within (Evoral::Range<samplepos_t>); boost::shared_ptr<RegionList> regions_with_end_within (Temporal::TimeRange);
uint32_t region_use_count (boost::shared_ptr<Region>) const; uint32_t region_use_count (boost::shared_ptr<Region>) const;
boost::shared_ptr<Region> find_region (const PBD::ID&) const; boost::shared_ptr<Region> find_region (const PBD::ID&) const;
boost::shared_ptr<Region> top_region_at (samplepos_t sample); boost::shared_ptr<Region> top_region_at (timepos_t const &);
boost::shared_ptr<Region> top_unmuted_region_at (samplepos_t sample); boost::shared_ptr<Region> top_unmuted_region_at (timepos_t const &);
boost::shared_ptr<Region> find_next_region (samplepos_t sample, RegionPoint point, int dir); boost::shared_ptr<Region> find_next_region (timepos_t const &, RegionPoint point, int dir);
samplepos_t find_next_region_boundary (samplepos_t sample, int dir); timepos_t find_next_region_boundary (timepos_t const &, int dir);
bool region_is_shuffle_constrained (boost::shared_ptr<Region>); bool region_is_shuffle_constrained (boost::shared_ptr<Region>);
bool has_region_at (samplepos_t const) const; bool has_region_at (timepos_t const &) const;
samplepos_t find_prev_region_start (samplepos_t sample); samplepos_t find_prev_region_start (samplepos_t sample);
bool uses_source (boost::shared_ptr<const Source> src, bool shallow = false) const; bool uses_source (boost::shared_ptr<const Source> src, bool shallow = false) const;
void deep_sources (std::set<boost::shared_ptr<Source> >&) const; void deep_sources (std::set<boost::shared_ptr<Source> >&) const;
samplepos_t find_next_transient (samplepos_t position, int dir); samplepos_t find_next_transient (timepos_t const & position, int dir);
void foreach_region (boost::function<void(boost::shared_ptr<Region>)>); void foreach_region (boost::function<void(boost::shared_ptr<Region>)>);
@ -252,12 +255,12 @@ public:
PBD::Signal0<void> LayeringChanged; PBD::Signal0<void> LayeringChanged;
/** Emitted when regions have moved (not when regions have only been trimmed) */ /** Emitted when regions have moved (not when regions have only been trimmed) */
PBD::Signal2<void, std::list<Evoral::RangeMove<samplepos_t> > const&, bool> RangesMoved; PBD::Signal2<void,std::list< Temporal::RangeMove> const &, bool> RangesMoved;
/** Emitted when regions are extended; the ranges passed are the new extra time ranges /** Emitted when regions are extended; the ranges passed are the new extra time ranges
that these regions now occupy. that these regions now occupy.
*/ */
PBD::Signal1<void, std::list<Evoral::Range<samplepos_t> > const&> RegionsExtended; PBD::Signal1<void,std::list< Temporal::Range> const &> RegionsExtended;
static std::string bump_name (std::string old_name, Session&); static std::string bump_name (std::string old_name, Session&);
@ -289,11 +292,8 @@ public:
return boost::shared_ptr<Crossfade> (); return boost::shared_ptr<Crossfade> ();
} }
samplepos_t find_next_top_layer_position (samplepos_t) const; timepos_t find_next_top_layer_position (timepos_t const &) const;
uint32_t combine_ops () const uint32_t combine_ops() const { return _combine_ops; }
{
return _combine_ops;
}
void set_layer (boost::shared_ptr<Region>, double); void set_layer (boost::shared_ptr<Region>, double);
@ -373,6 +373,7 @@ protected:
* region trims are not included in this list; it is used to * region trims are not included in this list; it is used to
* do automation-follows-regions. * do automation-follows-regions.
*/ */
std::list<Evoral::RangeMove<samplepos_t> > pending_range_moves; std::list<Evoral::RangeMove<samplepos_t> > pending_range_moves;
/** Extra sections added to regions during trims */ /** Extra sections added to regions during trims */
@ -393,6 +394,7 @@ protected:
uint32_t subcnt; uint32_t subcnt;
PBD::ID _orig_track_id; PBD::ID _orig_track_id;
uint32_t _combine_ops; uint32_t _combine_ops;
std::list<PBD::ID> _shared_with_ids; std::list<PBD::ID> _shared_with_ids;
void init (bool hide); void init (bool hide);
@ -410,7 +412,7 @@ protected:
void _set_sort_id (); void _set_sort_id ();
boost::shared_ptr<RegionList> regions_touched_locked (samplepos_t start, samplepos_t end); boost::shared_ptr<RegionList> regions_touched_locked (timepos_t const & start, timepos_t const & end);
void notify_region_removed (boost::shared_ptr<Region>); void notify_region_removed (boost::shared_ptr<Region>);
void notify_region_added (boost::shared_ptr<Region>); void notify_region_added (boost::shared_ptr<Region>);
@ -431,34 +433,34 @@ protected:
void sort_regions (); void sort_regions ();
void ripple_locked (timepos_t const & at, timecnt_t const & distance, RegionList *exclude);
void ripple_locked (samplepos_t at, samplecnt_t distance, RegionList* exclude); void ripple_unlocked (timepos_t const & at, timecnt_t const & distance, RegionList *exclude, Thawlist& thawlist);
bool ripple_unlocked (samplepos_t at, samplecnt_t distance, RegionList* exclude, ThawList& thawlist);
virtual void remove_dependents (boost::shared_ptr<Region> /*region*/) {} virtual void remove_dependents (boost::shared_ptr<Region> /*region*/) {}
virtual void region_going_away (boost::weak_ptr<Region> /*region*/) {} virtual void region_going_away (boost::weak_ptr<Region> /*region*/) {}
virtual XMLNode& state (bool); virtual XMLNode& state (bool);
bool add_region_internal (boost::shared_ptr<Region>, samplepos_t position, ThawList& thawlist, int32_t sub_num = 0, double quarter_note = 0.0, bool for_music = false); bool add_region_internal (boost::shared_ptr<Region>, timepos_t const & position, Thawlist& thawlist);
int remove_region_internal (boost::shared_ptr<Region>, ThawList& thawlist); int remove_region_internal (boost::shared_ptr<Region>, ThawList& thawlist);
void copy_regions (RegionList&) const; void copy_regions (RegionList&) const;
void partition_internal (samplepos_t start, samplepos_t end, bool cutting, ThawList& thawlist);
std::pair<samplepos_t, samplepos_t> _get_extent () const; void partition_internal (timepos_t const & start, timepos_t const & end, bool cutting, ThawList& thawlist);
boost::shared_ptr<Playlist> cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf) (samplepos_t, samplecnt_t, bool), std::pair<timepos_t, timepos_t> _get_extent() const;
std::list<AudioRange>& ranges, bool result_is_hidden);
boost::shared_ptr<Playlist> cut (samplepos_t start, samplecnt_t cnt, bool result_is_hidden); boost::shared_ptr<Playlist> cut_copy (boost::shared_ptr<Playlist> (Playlist::*pmf)(timepos_t const &, timecnt_t const &, bool),
boost::shared_ptr<Playlist> copy (samplepos_t start, samplecnt_t cnt, bool result_is_hidden); std::list<TimelineRange>& ranges, bool result_is_hidden);
boost::shared_ptr<Playlist> cut (timepos_t const & start, timecnt_t const & cnt, bool result_is_hidden);
boost::shared_ptr<Playlist> copy (timepos_t const & start, timecnt_t const & cnt, bool result_is_hidden);
void relayer (); void relayer ();
void begin_undo (); void begin_undo ();
void end_undo (); void end_undo ();
virtual void _split_region (boost::shared_ptr<Region>, const MusicSample& position, ThawList& thawlist); virtual void _split_region (boost::shared_ptr<Region>, timepos_t const & position, Thawlist& thawlist);
typedef std::pair<boost::shared_ptr<Region>, boost::shared_ptr<Region> > TwoRegions; typedef std::pair<boost::shared_ptr<Region>, boost::shared_ptr<Region> > TwoRegions;
@ -479,15 +481,13 @@ private:
private: private:
void freeze_locked (); void freeze_locked ();
void setup_layering_indices (RegionList const&); void setup_layering_indices (RegionList const &);
void coalesce_and_check_crossfades (std::list<Evoral::Range<samplepos_t> >); void coalesce_and_check_crossfades (std::list<Temporal::TimeRange>);
boost::shared_ptr<RegionList> find_regions_at (timepos_t const &);
boost::shared_ptr<RegionList> find_regions_at (samplepos_t); mutable boost::optional<std::pair<timepos_t, timepos_t> > _cached_extent;
timepos_t _end_space; //this is used when we are pasting a range with extra space at the end
mutable boost::optional<std::pair<samplepos_t, samplepos_t> > _cached_extent; bool _playlist_shift_active;
samplepos_t _end_space; // this is used when we are pasting a range with extra space at the end
bool _playlist_shift_active;
std::string _pgroup_id; // when we make multiple playlists in one action, they will share the same pgroup_id std::string _pgroup_id; // when we make multiple playlists in one action, they will share the same pgroup_id
}; };
@ -495,3 +495,4 @@ private:
} /* namespace ARDOUR */ } /* namespace ARDOUR */
#endif /* __ardour_playlist_h__ */ #endif /* __ardour_playlist_h__ */

View file

@ -37,7 +37,7 @@ class LIBARDOUR_API PlaylistFactory {
static boost::shared_ptr<Playlist> create (Session&, const XMLNode&, bool hidden = false, bool unused = false); static boost::shared_ptr<Playlist> create (Session&, const XMLNode&, bool hidden = false, bool unused = false);
static boost::shared_ptr<Playlist> create (DataType type, Session&, std::string name, bool hidden = false); static boost::shared_ptr<Playlist> create (DataType type, Session&, std::string name, bool hidden = false);
static boost::shared_ptr<Playlist> create (boost::shared_ptr<const Playlist>, std::string name, bool hidden = false); static boost::shared_ptr<Playlist> create (boost::shared_ptr<const Playlist>, std::string name, bool hidden = false);
static boost::shared_ptr<Playlist> create (boost::shared_ptr<const Playlist>, samplepos_t start, samplecnt_t cnt, std::string name, bool hidden = false); static boost::shared_ptr<Playlist> create (boost::shared_ptr<const Playlist>, timepos_t const & start, timepos_t const & cnt, std::string name, bool hidden = false);
}; };
} }

View file

@ -45,11 +45,11 @@ protected:
boost::shared_ptr<Playlist> _playlist; boost::shared_ptr<Playlist> _playlist;
PBD::ID _original; PBD::ID _original;
PBD::ID _owner; PBD::ID _owner;
sampleoffset_t _playlist_offset; timepos_t _playlist_offset;
samplecnt_t _playlist_length; timepos_t _playlist_length;
PlaylistSource (Session&, const PBD::ID&, const std::string& name, boost::shared_ptr<Playlist>, DataType, PlaylistSource (Session&, const PBD::ID&, const std::string& name, boost::shared_ptr<Playlist>, DataType,
sampleoffset_t begin, samplecnt_t len, Source::Flag flags); timepos_t const & begin, timepos_t const & len, Source::Flag flags);
PlaylistSource (Session&, const XMLNode&); PlaylistSource (Session&, const XMLNode&);
void add_state (XMLNode&); void add_state (XMLNode&);

View file

@ -88,7 +88,7 @@ public:
bool write_immediate_event (Evoral::EventType event_type, size_t size, const uint8_t* buf); bool write_immediate_event (Evoral::EventType event_type, size_t size, const uint8_t* buf);
void automation_run (samplepos_t, pframes_t, bool only_active = false); void automation_run (samplepos_t, pframes_t, bool only_active = false);
bool find_next_event (double, double, Evoral::ControlEvent&, bool only_active = true) const; bool find_next_event (Temporal::timepos_t const &, Temporal::timepos_t const &, Evoral::ControlEvent&, bool only_active = true) const;
int set_block_size (pframes_t nframes); int set_block_size (pframes_t nframes);

View file

@ -29,7 +29,7 @@ namespace ARDOUR {
class LIBARDOUR_API Quantize : public MidiOperator { class LIBARDOUR_API Quantize : public MidiOperator {
public: public:
Quantize (bool snap_start, bool snap_end, Quantize (bool snap_start, bool snap_end,
double start_grid, double end_grid, int start_grid, int end_grid,
float strength, float swing, Temporal::Beats const & threshold); float strength, float swing, Temporal::Beats const & threshold);
~Quantize (); ~Quantize ();
@ -41,8 +41,8 @@ public:
private: private:
bool _snap_start; bool _snap_start;
bool _snap_end; bool _snap_end;
double _start_grid; int _start_grid;
double _end_grid; int _end_grid;
float _strength; float _strength;
float _swing; float _swing;
Temporal::Beats _threshold; Temporal::Beats _threshold;

View file

@ -27,11 +27,11 @@ namespace ARDOUR {
class Session; class Session;
class LIBARDOUR_API Readable { class LIBARDOUR_API AudioReadable {
public: public:
virtual ~Readable() {} virtual ~AudioReadable() {}
static std::vector<boost::shared_ptr<Readable> > static std::vector<boost::shared_ptr<AudioReadable> >
load (Session&, std::string const&); load (Session&, std::string const&);
virtual samplecnt_t read (Sample*, samplepos_t pos, samplecnt_t cnt, int channel) const = 0; virtual samplecnt_t read (Sample*, samplepos_t pos, samplecnt_t cnt, int channel) const = 0;

View file

@ -71,7 +71,6 @@ namespace Properties {
LIBARDOUR_API extern PBD::PropertyDescriptor<timecnt_t> ancestral_length; LIBARDOUR_API extern PBD::PropertyDescriptor<timecnt_t> ancestral_length;
LIBARDOUR_API extern PBD::PropertyDescriptor<float> stretch; LIBARDOUR_API extern PBD::PropertyDescriptor<float> stretch;
LIBARDOUR_API extern PBD::PropertyDescriptor<float> shift; LIBARDOUR_API extern PBD::PropertyDescriptor<float> shift;
LIBARDOUR_API extern PBD::PropertyDescriptor<PositionLockStyle> position_lock_style;
LIBARDOUR_API extern PBD::PropertyDescriptor<uint64_t> layering_index; LIBARDOUR_API extern PBD::PropertyDescriptor<uint64_t> layering_index;
LIBARDOUR_API extern PBD::PropertyDescriptor<std::string> tags; LIBARDOUR_API extern PBD::PropertyDescriptor<std::string> tags;
LIBARDOUR_API extern PBD::PropertyDescriptor<bool> contents; // type doesn't matter here LIBARDOUR_API extern PBD::PropertyDescriptor<bool> contents; // type doesn't matter here
@ -92,7 +91,6 @@ enum LIBARDOUR_API RegionEditState {
class LIBARDOUR_API Region class LIBARDOUR_API Region
: public SessionObject : public SessionObject
, public boost::enable_shared_from_this<Region> , public boost::enable_shared_from_this<Region>
, public Readable
, public Trimmable , public Trimmable
, public Movable , public Movable
{ {
@ -123,6 +121,7 @@ public:
timecnt_t nt_start () const { return _start.val(); } timecnt_t nt_start () const { return _start.val(); }
timecnt_t nt_length () const { return _length.val(); } timecnt_t nt_length () const { return _length.val(); }
timepos_t nt_end() const; timepos_t nt_end() const;
timepos_t nt_last() const { return nt_end().decrement(); }
timepos_t source_position () const; timepos_t source_position () const;
timepos_t source_relative_position (Temporal::timepos_t const &) const; timepos_t source_relative_position (Temporal::timepos_t const &) const;
@ -132,8 +131,6 @@ public:
samplecnt_t start_sample () const { return _start.val().samples(); } samplecnt_t start_sample () const { return _start.val().samples(); }
samplecnt_t length_samples () const { return _length.val().samples(); } samplecnt_t length_samples () const { return _length.val().samples(); }
samplecnt_t readable_length_samples() const { return length_samples(); }
layer_t layer () const { return _layer; } layer_t layer () const { return _layer; }
void set_selected_for_solo(bool yn); void set_selected_for_solo(bool yn);
@ -180,7 +177,11 @@ public:
} }
Temporal::TimeRange range_samples () const { Temporal::TimeRange range_samples () const {
return Temporal::TimeRange (timepos_t::from_samples (first_sample()), timepos_t::from_samples (first_sample() + length_samples())); return Temporal::TimeRange (timepos_t (first_sample()), timepos_t (first_sample() + length_samples()));
}
Temporal::TimeRange range () const {
return Temporal::TimeRange (nt_position(), nt_position() + nt_length());
} }
bool hidden () const { return _hidden; } bool hidden () const { return _hidden; }
@ -199,9 +200,9 @@ public:
Trimmable::CanTrim can_trim () const; Trimmable::CanTrim can_trim () const;
PositionLockStyle position_lock_style () const { return _position_lock_style; } Temporal::TimeDomain position_time_domain () const;
void set_position_lock_style (PositionLockStyle ps); void set_position_time_domain (Temporal::TimeDomain ps);
void recompute_position_from_lock_style (); void recompute_position_from_time_domain ();
void suspend_property_changes (); void suspend_property_changes ();
@ -209,14 +210,18 @@ public:
return first_sample() <= sample && sample <= last_sample(); return first_sample() <= sample && sample <= last_sample();
} }
bool covers (timepos_t const & pos) const {
return nt_position() <= pos && pos <= nt_last();
}
/** @return coverage of this region with the given range; /** @return coverage of this region with the given range;
* OverlapInternal: the range is internal to this region. * OverlapInternal: the range is internal to this region.
* OverlapStart: the range overlaps the start of this region. * OverlapStart: the range overlaps the start of this region.
* OverlapEnd: the range overlaps the end of this region. * OverlapEnd: the range overlaps the end of this region.
* OverlapExternal: the range overlaps all of this region. * OverlapExternal: the range overlaps all of this region.
*/ */
Evoral::OverlapType coverage (samplepos_t start, samplepos_t end) const { Temporal::OverlapType coverage (timepos_t const & start, timepos_t const & end) const {
return Evoral::coverage (first_sample(), last_sample(), start, end); return Temporal::coverage_exclusive_ends (_position.val(), nt_last(), start, end);
} }
bool exact_equivalent (boost::shared_ptr<const Region>) const; bool exact_equivalent (boost::shared_ptr<const Region>) const;
@ -283,7 +288,6 @@ public:
bool is_compound () const; bool is_compound () const;
boost::shared_ptr<Source> source (uint32_t n=0) const { return _sources[ (n < _sources.size()) ? n : 0 ]; } boost::shared_ptr<Source> source (uint32_t n=0) const { return _sources[ (n < _sources.size()) ? n : 0 ]; }
uint32_t n_channels() const { return _sources.size(); }
SourceList& sources_for_edit () { return _sources; } SourceList& sources_for_edit () { return _sources; }
const SourceList& sources () const { return _sources; } const SourceList& sources () const { return _sources; }
@ -415,7 +419,6 @@ protected:
void send_change (const PBD::PropertyChange&); void send_change (const PBD::PropertyChange&);
virtual int _set_state (const XMLNode&, int version, PBD::PropertyChange& what_changed, bool send_signal); virtual int _set_state (const XMLNode&, int version, PBD::PropertyChange& what_changed, bool send_signal);
void post_set (const PBD::PropertyChange&);
virtual void set_position_internal (timepos_t const & pos); virtual void set_position_internal (timepos_t const & pos);
virtual void set_length_internal (timecnt_t const &); virtual void set_length_internal (timecnt_t const &);
virtual void set_start_internal (timecnt_t const &); virtual void set_start_internal (timecnt_t const &);
@ -458,7 +461,7 @@ protected:
private: private:
void mid_thaw (const PBD::PropertyChange&); void mid_thaw (const PBD::PropertyChange&);
virtual void trim_to_internal (timepos_t const & position, timecnt_t const & length); void trim_to_internal (timepos_t const & position, timecnt_t const & length);
void modify_front (timepos_t const & new_position, bool reset_fade); void modify_front (timepos_t const & new_position, bool reset_fade);
void modify_end (timepos_t const & new_position, bool reset_fade); void modify_end (timepos_t const & new_position, bool reset_fade);
@ -485,7 +488,6 @@ private:
PBD::Property<timecnt_t> _ancestral_length; PBD::Property<timecnt_t> _ancestral_length;
PBD::Property<float> _stretch; PBD::Property<float> _stretch;
PBD::Property<float> _shift; PBD::Property<float> _shift;
PBD::EnumProperty<PositionLockStyle> _position_lock_style;
PBD::Property<uint64_t> _layering_index; PBD::Property<uint64_t> _layering_index;
PBD::Property<std::string> _tags; PBD::Property<std::string> _tags;
PBD::Property<bool> _contents; // type is irrelevant PBD::Property<bool> _contents; // type is irrelevant

View file

@ -165,7 +165,7 @@ public:
/* end of vfunc-based API */ /* end of vfunc-based API */
void shift (samplepos_t, samplecnt_t); void shift (timepos_t const &, timecnt_t const &);
/* controls use set_solo() to modify this route's solo state */ /* controls use set_solo() to modify this route's solo state */

View file

@ -66,7 +66,7 @@
#include "lua/luastate.h" #include "lua/luastate.h"
#include "evoral/Range.h" #include "temporal/range.h"
#include "midi++/types.h" #include "midi++/types.h"
#include "midi++/mmc.h" #include "midi++/mmc.h"
@ -336,7 +336,7 @@ public:
StripableList get_stripables () const; StripableList get_stripables () const;
boost::shared_ptr<RouteList> get_tracks() const; boost::shared_ptr<RouteList> get_tracks() const;
boost::shared_ptr<RouteList> get_routes_with_internal_returns() const; boost::shared_ptr<RouteList> get_routes_with_internal_returns() const;
boost::shared_ptr<RouteList> get_routes_with_regions_at (samplepos_t const) const; boost::shared_ptr<RouteList> get_routes_with_regions_at (timepos_t const &) const;
boost::shared_ptr<AudioTrack> get_nth_audio_track (uint32_t) const; boost::shared_ptr<AudioTrack> get_nth_audio_track (uint32_t) const;
@ -528,7 +528,7 @@ public:
void set_auto_punch_location (Location *); void set_auto_punch_location (Location *);
void set_auto_loop_location (Location *); void set_auto_loop_location (Location *);
void set_session_extents (samplepos_t start, samplepos_t end); void set_session_extents (timepos_t const & start, timepos_t const & end);
bool session_range_is_free () const { return _session_range_is_free; } bool session_range_is_free () const { return _session_range_is_free; }
void set_session_range_is_free (bool); void set_session_range_is_free (bool);
@ -1122,11 +1122,11 @@ public:
/* ranges */ /* ranges */
void request_play_range (std::list<AudioRange>*, bool leave_rolling = false); void request_play_range (std::list<TimelineRange>*, bool leave_rolling = false);
void request_cancel_play_range (); void request_cancel_play_range ();
bool get_play_range () const { return _play_range; } bool get_play_range () const { return _play_range; }
void maybe_update_session_range (samplepos_t, samplepos_t); void maybe_update_session_range (timepos_t const &, timepos_t const &);
/* preroll */ /* preroll */
samplecnt_t preroll_samples (samplepos_t) const; samplecnt_t preroll_samples (samplepos_t) const;
@ -1311,7 +1311,7 @@ public:
void import_pt_sources (PTFFormat& ptf, ImportStatus& status); void import_pt_sources (PTFFormat& ptf, ImportStatus& status);
void import_pt_rest (PTFFormat& ptf); void import_pt_rest (PTFFormat& ptf);
bool import_sndfile_as_region (std::string path, SrcQuality quality, samplepos_t& pos, SourceList& sources, ImportStatus& status, uint32_t current, uint32_t total); bool import_sndfile_as_region (std::string path, SrcQuality quality, timepos_t& pos, SourceList& sources, ImportStatus& status, uint32_t current, uint32_t total);
struct ptflookup { struct ptflookup {
uint16_t index1; uint16_t index1;
@ -1965,8 +1965,8 @@ private:
void remove_playlist (boost::weak_ptr<Playlist>); void remove_playlist (boost::weak_ptr<Playlist>);
void track_playlist_changed (boost::weak_ptr<Track>); void track_playlist_changed (boost::weak_ptr<Track>);
void playlist_region_added (boost::weak_ptr<Region>); void playlist_region_added (boost::weak_ptr<Region>);
void playlist_ranges_moved (std::list<Evoral::RangeMove<samplepos_t> > const &); void playlist_ranges_moved (std::list<Temporal::RangeMove> const &);
void playlist_regions_extended (std::list<Evoral::Range<samplepos_t> > const &); void playlist_regions_extended (std::list<Temporal::Range> const &);
/* CURVES and AUTOMATION LISTS */ /* CURVES and AUTOMATION LISTS */
std::map<PBD::ID, AutomationList*> automation_lists; std::map<PBD::ID, AutomationList*> automation_lists;
@ -2106,16 +2106,16 @@ private:
/* range playback */ /* range playback */
std::list<AudioRange> current_audio_range; std::list<TimelineRange> current_audio_range;
bool _play_range; bool _play_range;
void set_play_range (std::list<AudioRange>&, bool leave_rolling); void set_play_range (std::list<TimelineRange>&, bool leave_rolling);
void unset_play_range (); void unset_play_range ();
/* temporary hacks to allow selection to be pushed from GUI into backend /* temporary hacks to allow selection to be pushed from GUI into backend
Whenever we move the selection object into libardour, these will go away. Whenever we move the selection object into libardour, these will go away.
*/ */
Evoral::Range<samplepos_t> _range_selection; Temporal::Range _range_selection;
Evoral::Range<samplepos_t> _object_selection; Temporal::Range _object_selection;
void unset_preroll_record_trim (); void unset_preroll_record_trim ();

View file

@ -114,8 +114,8 @@ public:
RTeventCallback rt_return; /* called after rt_slot, with this event as an argument */ RTeventCallback rt_return; /* called after rt_slot, with this event as an argument */
PBD::EventLoop* event_loop; PBD::EventLoop* event_loop;
std::list<AudioRange> audio_range; std::list<TimelineRange> audio_range;
std::list<MusicRange> music_range; std::list<TimelineRange> music_range;
boost::shared_ptr<Region> region; boost::shared_ptr<Region> region;
boost::shared_ptr<TransportMaster> transport_master; boost::shared_ptr<TransportMaster> transport_master;

View file

@ -54,7 +54,7 @@ protected:
} }
samplecnt_t read_unlocked (Sample *dst, samplepos_t start, samplecnt_t cnt) const { samplecnt_t read_unlocked (Sample *dst, samplepos_t start, samplecnt_t cnt) const {
cnt = std::min (cnt, std::max<samplecnt_t> (0, _length - start)); cnt = std::min (cnt, std::max<samplecnt_t> (0, _length.samples() - start));
memset (dst, 0, sizeof (Sample) * cnt); memset (dst, 0, sizeof (Sample) * cnt);
return cnt; return cnt;
} }

View file

@ -76,13 +76,13 @@ public:
int set_state (XMLNode const&, int); int set_state (XMLNode const&, int);
XMLNode& get_state(); XMLNode& get_state();
bool find_next_event (double n, double e, Evoral::ControlEvent& ev) const bool find_next_event (Temporal::timepos_t const & n, Temporal::timepos_t const & e, Evoral::ControlEvent& ev) const
{ {
Glib::Threads::RWLock::ReaderLock lm (master_lock); Glib::Threads::RWLock::ReaderLock lm (master_lock);
return find_next_event_locked (n, e, ev); return find_next_event_locked (n, e, ev);
} }
bool find_next_event_locked (double now, double end, Evoral::ControlEvent& next_event) const; bool find_next_event_locked (Temporal::timepos_t const & now, Temporal::timepos_t const & end, Evoral::ControlEvent& next_event) const;
protected: protected:
@ -136,7 +136,7 @@ protected:
void update_boolean_masters_records (boost::shared_ptr<AutomationControl>); void update_boolean_masters_records (boost::shared_ptr<AutomationControl>);
virtual bool get_masters_curve_locked (samplepos_t, samplepos_t, float*, samplecnt_t) const; virtual bool get_masters_curve_locked (samplepos_t, samplepos_t, float*, samplecnt_t) const;
bool masters_curve_multiply (samplepos_t, samplepos_t, float*, samplecnt_t) const; bool masters_curve_multiply (timepos_t const &, timepos_t const &, float*, samplecnt_t) const;
virtual double reduce_by_masters_locked (double val, bool) const; virtual double reduce_by_masters_locked (double val, bool) const;
virtual double scale_automation_callback (double val, double ratio) const; virtual double scale_automation_callback (double val, double ratio) const;

View file

@ -80,34 +80,33 @@ public:
private: private:
bool _open; bool _open;
Temporal::Beats _last_ev_time_beats; Temporal::Beats _last_ev_time_beats;
samplepos_t _last_ev_time_samples; samplepos_t _last_ev_time_samples;
/** end time (start + duration) of last call to read_unlocked */ /** end time (start + duration) of last call to read_unlocked */
mutable samplepos_t _smf_last_read_end; mutable timecnt_t _smf_last_read_end;
/** time (in SMF ticks, 1 tick per _ppqn) of the last event read by read_unlocked */ /** time (in SMF ticks, 1 tick per _ppqn) of the last event read by read_unlocked */
mutable samplepos_t _smf_last_read_time; mutable timepos_t _smf_last_read_time;
int open_for_write (); int open_for_write ();
void ensure_disk_file (const Lock& lock); void ensure_disk_file (const Lock& lock);
samplecnt_t read_unlocked (const Lock& lock, timecnt_t read_unlocked (const Lock& lock,
Evoral::EventSink<samplepos_t>& dst, Evoral::EventSink<samplepos_t>& dst,
samplepos_t position, timepos_t const & position,
samplepos_t start, timecnt_t const & start,
samplecnt_t cnt, timecnt_t const & cnt,
Evoral::Range<samplepos_t>* loop_range, Temporal::Range* loop_range,
MidiStateTracker* tracker, MidiStateTracker* tracker,
MidiChannelFilter* filter) const; MidiChannelFilter* filter) const;
samplecnt_t write_unlocked (const Lock& lock, timecnt_t write_unlocked (const Lock& lock,
MidiRingBuffer<samplepos_t>& src, MidiRingBuffer<samplepos_t>& src,
samplepos_t position, timepos_t const & position,
samplecnt_t cnt); timecnt_t const & cnt);
}; };
}; /* namespace ARDOUR */ }; /* namespace ARDOUR */
#endif /* __ardour_smf_source_h__ */ #endif /* __ardour_smf_source_h__ */

View file

@ -94,7 +94,7 @@ class LIBARDOUR_API SndFileSource : public AudioFileSource {
int setup_broadcast_info (samplepos_t when, struct tm&, time_t); int setup_broadcast_info (samplepos_t when, struct tm&, time_t);
void file_closed (); void file_closed ();
void set_natural_position (samplepos_t); void set_natural_position (timepos_t const &);
samplecnt_t nondestructive_write_unlocked (Sample *dst, samplecnt_t cnt); samplecnt_t nondestructive_write_unlocked (Sample *dst, samplecnt_t cnt);
PBD::ScopedConnection header_position_connection; PBD::ScopedConnection header_position_connection;
}; };

View file

@ -74,9 +74,11 @@ public:
time_t timestamp() const { return _timestamp; } time_t timestamp() const { return _timestamp; }
void stamp (time_t when) { _timestamp = when; } void stamp (time_t when) { _timestamp = when; }
virtual bool empty () const = 0; timecnt_t length() const;
virtual samplecnt_t length (samplepos_t pos) const = 0;
virtual void update_length (samplecnt_t cnt) = 0; virtual bool empty () const;
virtual samplecnt_t length_samples (timepos_t const & pos) const { return _length.samples(); };
virtual void update_length (timecnt_t const & cnt) {}
void set_take_id (std::string id) { _take_id =id; } void set_take_id (std::string id) { _take_id =id; }
const std::string& take_id () const { return _take_id; } const std::string& take_id () const { return _take_id; }
@ -114,14 +116,15 @@ public:
CueMarkers const & cue_markers() const { return _cue_markers; } CueMarkers const & cue_markers() const { return _cue_markers; }
bool add_cue_marker (CueMarker const &); bool add_cue_marker (CueMarker const &);
bool move_cue_marker (CueMarker const &, samplepos_t source_relative_position); bool move_cue_marker (CueMarker const &, timepos_t const & source_relative_position);
bool remove_cue_marker (CueMarker const &); bool remove_cue_marker (CueMarker const &);
bool rename_cue_marker (CueMarker&, std::string const &); bool rename_cue_marker (CueMarker&, std::string const &);
bool clear_cue_markers (); bool clear_cue_markers ();
PBD::Signal0<void> CueMarkersChanged; PBD::Signal0<void> CueMarkersChanged;
virtual samplepos_t natural_position() const { return _natural_position; } virtual timepos_t natural_position() const { return _natural_position; }
virtual void set_natural_position (samplepos_t pos); virtual void set_natural_position (timepos_t const & pos);
bool have_natural_position() const { return _have_natural_position; } bool have_natural_position() const { return _have_natural_position; }
void set_allow_remove_if_empty (bool yn); void set_allow_remove_if_empty (bool yn);
@ -143,19 +146,19 @@ public:
std::string captured_for() const { return _captured_for; } std::string captured_for() const { return _captured_for; }
protected: protected:
DataType _type; DataType _type;
Flag _flags; Flag _flags;
time_t _timestamp; time_t _timestamp;
std::string _take_id; std::string _take_id;
samplepos_t _natural_position; timepos_t _natural_position;
samplepos_t _have_natural_position; bool _have_natural_position;
bool _analysed; bool _analysed;
GATOMIC_QUAL gint _use_count; /* atomic */ GATOMIC_QUAL gint _use_count; /* atomic */
uint32_t _level; /* how deeply nested is this source w.r.t a disk file */ uint32_t _level; /* how deeply nested is this source w.r.t a disk file */
std::string _ancestor_name; std::string _ancestor_name;
std::string _captured_for; std::string _captured_for;
XrunPositions _xruns; timecnt_t _length;
CueMarkers _cue_markers; XrunPositions _xruns;
mutable Glib::Threads::Mutex _lock; mutable Glib::Threads::Mutex _lock;
mutable Glib::Threads::Mutex _analysis_lock; mutable Glib::Threads::Mutex _analysis_lock;

View file

@ -62,7 +62,7 @@ class LIBARDOUR_API SourceFactory {
static boost::shared_ptr<Source> createFromPlaylist static boost::shared_ptr<Source> createFromPlaylist
(DataType type, Session& s, boost::shared_ptr<Playlist> p, const PBD::ID& orig, const std::string& name, (DataType type, Session& s, boost::shared_ptr<Playlist> p, const PBD::ID& orig, const std::string& name,
uint32_t chn, sampleoffset_t start, samplecnt_t len, bool copy, bool defer_peaks); uint32_t chn, timepos_t start, timepos_t const & len, bool copy, bool defer_peaks);
static Glib::Threads::Cond PeaksToBuild; static Glib::Threads::Cond PeaksToBuild;
static Glib::Threads::Mutex peak_building_lock; static Glib::Threads::Mutex peak_building_lock;

View file

@ -42,9 +42,9 @@ public:
float sample_rate () const { return _session.nominal_sample_rate(); } float sample_rate () const { return _session.nominal_sample_rate(); }
samplepos_t natural_position() const { return _source->natural_position() * _ratio;} timepos_t natural_position() const { return _source->natural_position() * _ratio;}
samplecnt_t readable_length() const { return _source->readable_length() * _ratio; } samplecnt_t readable_length_samples() const { return _source->length_samples (timepos_t (Temporal::AudioTime)) * _ratio; }
samplecnt_t length (samplepos_t pos) const { return _source->length(pos) * _ratio; } samplecnt_t length (samplepos_t /*pos*/) const { return _source->length_samples (timepos_t (Temporal::AudioTime)) * _ratio; }
bool can_be_analysed() const { return false; } bool can_be_analysed() const { return false; }
bool clamped_at_unity() const { return false; } bool clamped_at_unity() const { return false; }

View file

@ -50,6 +50,11 @@ class XMLNode;
namespace ARDOUR { namespace ARDOUR {
enum PositionLockStyle {
AudioTime,
MusicTime
};
class Meter; class Meter;
class TempoMap; class TempoMap;

View file

@ -19,15 +19,21 @@
#ifndef __libardour_timefx_request_h__ #ifndef __libardour_timefx_request_h__
#define __libardour_timefx_request_h__ #define __libardour_timefx_request_h__
#include "temporal/types.h"
#include "ardour/interthread_info.h" #include "ardour/interthread_info.h"
namespace ARDOUR { namespace ARDOUR {
struct TimeFXRequest : public InterThreadInfo { struct TimeFXRequest : public InterThreadInfo {
TimeFXRequest() TimeFXRequest()
: time_fraction(0), pitch_fraction(0), : time_fraction(0,0)
use_soundtouch(false), quick_seek(false), antialias(false), opts(0) {} , pitch_fraction(0)
float time_fraction; , use_soundtouch(false)
, quick_seek(false)
, antialias(false)
, opts(0) {}
Temporal::ratio_t time_fraction;
float pitch_fraction; float pitch_fraction;
/* SoundTouch */ /* SoundTouch */
bool use_soundtouch; bool use_soundtouch;

View file

@ -25,7 +25,7 @@
namespace ARDOUR { namespace ARDOUR {
class AudioSource; class AudioSource;
class Readable; class AudioReadable;
class Session; class Session;
class LIBARDOUR_API TransientDetector : public AudioAnalyser class LIBARDOUR_API TransientDetector : public AudioAnalyser
@ -39,8 +39,8 @@ public:
void set_threshold (float); void set_threshold (float);
void set_sensitivity (uint32_t, float); void set_sensitivity (uint32_t, float);
int run (const std::string& path, Readable*, uint32_t channel, AnalysisFeatureList& results); int run (const std::string& path, AudioReadable*, uint32_t channel, AnalysisFeatureList& results);
void update_positions (Readable* src, uint32_t channel, AnalysisFeatureList& results); void update_positions (AudioReadable* src, uint32_t channel, AnalysisFeatureList& results);
static void cleanup_transients (AnalysisFeatureList&, float sr, float gap_msecs); static void cleanup_transients (AnalysisFeatureList&, float sr, float gap_msecs);

View file

@ -43,6 +43,7 @@
#include <inttypes.h> #include <inttypes.h>
#include "temporal/bbt_time.h" #include "temporal/bbt_time.h"
#include "temporal/range.h"
#include "temporal/superclock.h" #include "temporal/superclock.h"
#include "temporal/time.h" #include "temporal/time.h"
#include "temporal/timeline.h" #include "temporal/timeline.h"
@ -51,8 +52,6 @@
#include "pbd/id.h" #include "pbd/id.h"
#include "pbd/microseconds.h" #include "pbd/microseconds.h"
#include "evoral/Range.h"
#include "ardour/chan_count.h" #include "ardour/chan_count.h"
#include "ardour/plugin_types.h" #include "ardour/plugin_types.h"
@ -355,64 +354,41 @@ struct MusicSample {
MusicSample operator- (MusicSample other) { return MusicSample (sample - other.sample, 0); } MusicSample operator- (MusicSample other) { return MusicSample (sample - other.sample, 0); }
}; };
/* XXX: slightly unfortunate that there is this and Evoral::Range<>, /* Just a Temporal::Range with an ID for identity
but this has a uint32_t id which Evoral::Range<> does not. */
*/ struct TimelineRange : public Temporal::TimeRange
struct AudioRange { {
samplepos_t start;
samplepos_t end;
uint32_t id; uint32_t id;
AudioRange (samplepos_t s, samplepos_t e, uint32_t i) : start (s), end (e) , id (i) {} TimelineRange (Temporal::timepos_t const & s, Temporal::timepos_t e, uint32_t i) : Temporal::TimeRange (s, e), id (i) {}
samplecnt_t length() const { return end - start + 1; } samplecnt_t length_samples() const { return length().samples(); }
bool operator== (const AudioRange& other) const { bool operator== (const TimelineRange& other) const {
return start == other.start && end == other.end && id == other.id; return id == other.id && Temporal::TimeRange::operator== (other);
} }
bool equal (const AudioRange& other) const { bool equal (const TimelineRange& other) const {
return start == other.start && end == other.end; return Temporal::TimeRange::operator== (other);
}
Evoral::OverlapType coverage (samplepos_t s, samplepos_t e) const {
return Evoral::coverage (start, end, s, e);
}
};
struct MusicRange {
Temporal::BBT_Time start;
Temporal::BBT_Time end;
uint32_t id;
MusicRange (Temporal::BBT_Time& s, Temporal::BBT_Time& e, uint32_t i)
: start (s), end (e), id (i) {}
bool operator== (const MusicRange& other) const {
return start == other.start && end == other.end && id == other.id;
}
bool equal (const MusicRange& other) const {
return start == other.start && end == other.end;
} }
}; };
class CueMarker { class CueMarker {
public: public:
CueMarker (std::string const& text, samplepos_t position) : _text (text), _position (position) {} CueMarker (std::string const& text, timepos_t const & position) : _text (text), _position (position) {}
std::string text() const { return _text; } std::string text() const { return _text; }
void set_text (std::string const & str) { _text = str; } void set_text (std::string const & str) { _text = str; }
samplepos_t position() const { return _position; } timepos_t position() const { return _position; }
void set_position (samplepos_t pos) { _position = pos; } void set_position (timepos_t const & pos) { _position = pos; }
bool operator== (CueMarker const & other) const { return _position == other.position() && _text == other.text(); } bool operator== (CueMarker const & other) const { return _position == other.position() && _text == other.text(); }
bool operator< (CueMarker const & other) const { return _position < other.position(); } bool operator< (CueMarker const & other) const { return _position < other.position(); }
private: private:
std::string _text; std::string _text;
samplepos_t _position; timepos_t _position;
}; };
typedef std::set<CueMarker> CueMarkers; typedef std::set<CueMarker> CueMarkers;
@ -692,11 +668,6 @@ struct CleanupReport {
size_t space; size_t space;
}; };
enum PositionLockStyle {
AudioTime,
MusicTime
};
/** A struct used to describe changes to processors in a route. /** A struct used to describe changes to processors in a route.
* This is useful because objects that respond to a change in processors * This is useful because objects that respond to a change in processors
* can optimise what work they do based on details of what has changed. * can optimise what work they do based on details of what has changed.

View file

@ -51,7 +51,6 @@ DEFINE_ENUM_CONVERT(ARDOUR::SyncSource)
DEFINE_ENUM_CONVERT(ARDOUR::ShuttleUnits) DEFINE_ENUM_CONVERT(ARDOUR::ShuttleUnits)
DEFINE_ENUM_CONVERT(ARDOUR::ClockDeltaMode) DEFINE_ENUM_CONVERT(ARDOUR::ClockDeltaMode)
DEFINE_ENUM_CONVERT(ARDOUR::DenormalModel) DEFINE_ENUM_CONVERT(ARDOUR::DenormalModel)
DEFINE_ENUM_CONVERT(ARDOUR::PositionLockStyle)
DEFINE_ENUM_CONVERT(ARDOUR::FadeShape) DEFINE_ENUM_CONVERT(ARDOUR::FadeShape)
DEFINE_ENUM_CONVERT(ARDOUR::RegionSelectionAfterSplit) DEFINE_ENUM_CONVERT(ARDOUR::RegionSelectionAfterSplit)
DEFINE_ENUM_CONVERT(ARDOUR::RangeSelectionAfterSplit) DEFINE_ENUM_CONVERT(ARDOUR::RangeSelectionAfterSplit)
@ -88,7 +87,7 @@ inline std::string to_string (ARDOUR::timepos_t val)
template <> template <>
inline ARDOUR::timepos_t string_to (std::string const & str) inline ARDOUR::timepos_t string_to (std::string const & str)
{ {
ARDOUR::timepos_t tmp; ARDOUR::timepos_t tmp (Temporal::AudioTime); /* domain may be changed */
tmp.string_to (str); tmp.string_to (str);
return tmp; return tmp;
} }
@ -116,7 +115,7 @@ inline std::string to_string (ARDOUR::timecnt_t val)
template <> template <>
inline ARDOUR::timecnt_t string_to (std::string const & str) inline ARDOUR::timecnt_t string_to (std::string const & str)
{ {
ARDOUR::timecnt_t tmp; ARDOUR::timecnt_t tmp (Temporal::AudioTime); /* domain may change */
tmp.string_to (str); tmp.string_to (str);
return tmp; return tmp;
} }

View file

@ -67,13 +67,14 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, stri
{ {
} }
AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, samplepos_t start, samplecnt_t cnt, string name, bool hidden) AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, timepos_t const & start, timepos_t const & cnt, string name, bool hidden)
: Playlist (other, start, cnt, name, hidden) : Playlist (other, start, cnt, name, hidden)
{ {
RegionReadLock rlock2 (const_cast<AudioPlaylist*> (other.get())); RegionReadLock rlock2 (const_cast<AudioPlaylist*> (other.get()));
in_set_state++; in_set_state++;
samplepos_t const end = start + cnt - 1; const timepos_t tend = start + cnt;
samplepos_t end = tend.samples();
/* Audio regions that have been created by the Playlist constructor /* Audio regions that have been created by the Playlist constructor
will currently have the same fade in/out as the regions that they will currently have the same fade in/out as the regions that they
@ -89,43 +90,46 @@ AudioPlaylist::AudioPlaylist (boost::shared_ptr<const AudioPlaylist> other, samp
samplecnt_t fade_in = 64; samplecnt_t fade_in = 64;
samplecnt_t fade_out = 64; samplecnt_t fade_out = 64;
switch (region->coverage (start, end)) { switch (region->coverage (start, tend)) {
case Evoral::OverlapNone: case Temporal::OverlapNone:
continue; continue;
case Evoral::OverlapInternal: case Temporal::OverlapInternal:
{ {
samplecnt_t const offset = start - region->position (); samplecnt_t const offset = start.samples() - region->position_sample ();
samplecnt_t const trim = region->last_sample() - end; samplecnt_t const trim = region->last_sample() - end;
if (region->fade_in()->back()->when > offset) { if (region->fade_in()->back()->when > offset) {
fade_in = region->fade_in()->back()->when - offset; fade_in = region->fade_in()->back()->when.earlier (timepos_t (offset)).samples();
} }
if (region->fade_out()->back()->when > trim) { if (region->fade_out()->back()->when > trim) {
fade_out = region->fade_out()->back()->when - trim; fade_out = region->fade_out()->back()->when.earlier (timepos_t (trim)).samples();
} }
break; break;
} }
case Evoral::OverlapStart: { case Temporal::OverlapStart: {
if (end > region->position() + region->fade_in()->back()->when) if (timepos_t (end) > region->nt_position() + region->fade_in()->back()->when) {
fade_in = region->fade_in()->back()->when; //end is after fade-in, preserve the fade-in fade_in = region->fade_in()->back()->when.samples(); //end is after fade-in, preserve the fade-in
if (end > region->last_sample() - region->fade_out()->back()->when) }
fade_out = region->fade_out()->back()->when - ( region->last_sample() - end ); //end is inside the fadeout, preserve the fades endpoint if (timepos_t (end) >= region->nt_end().earlier (region->fade_out()->back()->when)) {
fade_out = region->fade_out()->back()->when.earlier (timepos_t (region->last_sample() - end)).samples(); //end is inside the fadeout, preserve the fades endpoint
}
break; break;
} }
case Evoral::OverlapEnd: { case Temporal::OverlapEnd: {
if (start < region->last_sample() - region->fade_out()->back()->when) //start is before fade-out, preserve the fadeout if (start < region->nt_end().earlier (region->fade_out()->back()->when)) { //start is before fade-out, preserve the fadeout
fade_out = region->fade_out()->back()->when; fade_out = region->fade_out()->back()->when.samples();
}
if (start < region->position() + region->fade_in()->back()->when) if (start < region->nt_position() + region->fade_in()->back()->when) {
fade_in = region->fade_in()->back()->when - (start - region->position()); //end is inside the fade-in, preserve the fade-in endpoint fade_in = region->fade_in()->back()->when.earlier (start.distance (region->nt_position())).samples(); //end is inside the fade-in, preserve the fade-in endpoint
}
break; break;
} }
case Evoral::OverlapExternal: case Temporal::OverlapExternal:
fade_in = region->fade_in()->back()->when; fade_in = region->fade_in()->back()->when.samples();
fade_out = region->fade_out()->back()->when; fade_out = region->fade_out()->back()->when.samples();
break; break;
} }
@ -149,23 +153,23 @@ struct ReadSorter {
return a->layer() > b->layer(); return a->layer() > b->layer();
} }
return a->position() < b->position(); return a->nt_position() < b->nt_position();
} }
}; };
/** A segment of region that needs to be read */ /** A segment of region that needs to be read */
struct Segment { struct Segment {
Segment (boost::shared_ptr<AudioRegion> r, Evoral::Range<samplepos_t> a) : region (r), range (a) {} Segment (boost::shared_ptr<AudioRegion> r, Temporal::Range a) : region (r), range (a) {}
boost::shared_ptr<AudioRegion> region; ///< the region boost::shared_ptr<AudioRegion> region; ///< the region
Evoral::Range<samplepos_t> range; ///< range of the region to read, in session samples Temporal::Range range; ///< range of the region to read, in session samples
}; };
/** @param start Start position in session samples. /** @param start Start position in session samples.
* @param cnt Number of samples to read. * @param cnt Number of samples to read.
*/ */
ARDOUR::samplecnt_t ARDOUR::timecnt_t
AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, samplepos_t start, samplecnt_t cnt, unsigned chan_n) AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, timepos_t const & start, timecnt_t const & cnt, uint32_t chan_n)
{ {
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Playlist %1 read @ %2 for %3, channel %4, regions %5 mixdown @ %6 gain @ %7\n", DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Playlist %1 read @ %2 for %3, channel %4, regions %5 mixdown @ %6 gain @ %7\n",
name(), start, cnt, chan_n, regions.size(), mixdown_buffer, gain_buffer)); name(), start, cnt, chan_n, regions.size(), mixdown_buffer, gain_buffer));
@ -183,7 +187,7 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, sa
zeroed. zeroed.
*/ */
memset (buf, 0, sizeof (Sample) * cnt); memset (buf, 0, sizeof (Sample) * cnt.samples());
/* this function is never called from a realtime thread, so /* this function is never called from a realtime thread, so
its OK to block (for short intervals). its OK to block (for short intervals).
@ -194,14 +198,14 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, sa
/* Find all the regions that are involved in the bit we are reading, /* Find all the regions that are involved in the bit we are reading,
and sort them by descending layer and ascending position. and sort them by descending layer and ascending position.
*/ */
boost::shared_ptr<RegionList> all = regions_touched_locked (start, start + cnt - 1); boost::shared_ptr<RegionList> all = regions_touched_locked (start, start + cnt);
all->sort (ReadSorter ()); all->sort (ReadSorter ());
/* This will be a list of the bits of our read range that we have /* This will be a list of the bits of our read range that we have
handled completely (ie for which no more regions need to be read). handled completely (ie for which no more regions need to be read).
It is a list of ranges in session samples. It is a list of ranges in session samples.
*/ */
Evoral::RangeList<samplepos_t> done; Temporal::RangeList done;
/* This will be a list of the bits of regions that we need to read */ /* This will be a list of the bits of regions that we need to read */
list<Segment> to_do; list<Segment> to_do;
@ -224,30 +228,31 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, sa
/* Work out which bits of this region need to be read; /* Work out which bits of this region need to be read;
first, trim to the range we are reading... first, trim to the range we are reading...
*/ */
Evoral::Range<samplepos_t> region_range = ar->range (); Temporal::Range rrange = ar->range_samples ();
region_range.from = max (region_range.from, start); Temporal::Range region_range (max (rrange.start(), start),
region_range.to = min (region_range.to, start + cnt - 1); min (rrange.end(), start + cnt));
/* ... and then remove the bits that are already done */ /* ... and then remove the bits that are already done */
Evoral::RangeList<samplepos_t> region_to_do = Evoral::subtract (region_range, done); Temporal::RangeList region_to_do = region_range.subtract (done);
/* Make a note to read those bits, adding their bodies (the parts between end-of-fade-in /* Make a note to read those bits, adding their bodies (the parts between end-of-fade-in
and start-of-fade-out) to the `done' list. and start-of-fade-out) to the `done' list.
*/ */
Evoral::RangeList<samplepos_t>::List t = region_to_do.get (); Temporal::RangeList::List t = region_to_do.get ();
for (Evoral::RangeList<samplepos_t>::List::iterator j = t.begin(); j != t.end(); ++j) { for (Temporal::RangeList::List::iterator j = t.begin(); j != t.end(); ++j) {
Evoral::Range<samplepos_t> d = *j; Temporal::Range d = *j;
to_do.push_back (Segment (ar, d)); to_do.push_back (Segment (ar, d));
if (ar->opaque ()) { if (ar->opaque ()) {
/* Cut this range down to just the body and mark it done */ /* Cut this range down to just the body and mark it done */
Evoral::Range<samplepos_t> body = ar->body_range (); Temporal::Range body = ar->body_range ();
if (body.from < d.to && body.to > d.from) {
d.from = max (d.from, body.from); if (body.start() < d.end() && body.end() > d.start()) {
d.to = min (d.to, body.to); d.set_start (max (d.start(), body.start()));
d.set_end (min (d.end(), body.end()));
done.add (d); done.add (d);
} }
} }
@ -255,12 +260,14 @@ AudioPlaylist::read (Sample *buf, Sample *mixdown_buffer, float *gain_buffer, sa
} }
/* Now go backwards through the to_do list doing the actual reads */ /* Now go backwards through the to_do list doing the actual reads */
for (list<Segment>::reverse_iterator i = to_do.rbegin(); i != to_do.rend(); ++i) { for (list<Segment>::reverse_iterator i = to_do.rbegin(); i != to_do.rend(); ++i) {
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\tPlaylist %1 read %2 @ %3 for %4, channel %5, buf @ %6 offset %7\n", DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\tPlaylist %1 read %2 @ %3 for %4, channel %5, buf @ %6 offset %7\n",
name(), i->region->name(), i->range.from, name(), i->region->name(), i->range.start(),
i->range.to - i->range.from + 1, (int) chan_n, i->range.length(), (int) chan_n,
buf, i->range.from - start)); buf, i->range.start().earlier (start)));
i->region->read_at (buf + i->range.from - start, mixdown_buffer, gain_buffer, i->range.from, i->range.to - i->range.from + 1, chan_n);
i->region->read_at (buf + start.distance (i->range.start()).samples(), mixdown_buffer, gain_buffer, i->range.start().samples(), i->range.start().distance (i->range.end()).samples(), chan_n);
} }
return cnt; return cnt;
@ -278,9 +285,9 @@ AudioPlaylist::dump () const
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
r = *i; r = *i;
cerr << " " << r->name() << " @ " << r << " [" cerr << " " << r->name() << " @ " << r << " ["
<< r->start() << "+" << r->length() << r->nt_start() << "+" << r->nt_length()
<< "] at " << "] at "
<< r->position() << r->nt_position()
<< " on layer " << " on layer "
<< r->layer () << r->layer ()
<< endl; << endl;
@ -460,7 +467,7 @@ AudioPlaylist::pre_uncombine (vector<boost::shared_ptr<Region> >& originals, boo
original region. original region.
*/ */
if (cr->fade_in()->back()->when <= ar->length()) { if (cr->fade_in()->back()->when <= ar->nt_length()) {
/* don't do this if the fade is longer than the /* don't do this if the fade is longer than the
* region * region
*/ */
@ -474,7 +481,7 @@ AudioPlaylist::pre_uncombine (vector<boost::shared_ptr<Region> >& originals, boo
original region. original region.
*/ */
if (cr->fade_out()->back()->when <= ar->length()) { if (cr->fade_out()->back()->when <= ar->nt_length()) {
/* don't do this if the fade is longer than the /* don't do this if the fade is longer than the
* region * region
*/ */

View file

@ -45,13 +45,14 @@ using namespace ARDOUR;
using namespace PBD; using namespace PBD;
AudioPlaylistSource::AudioPlaylistSource (Session& s, const ID& orig, const std::string& name, boost::shared_ptr<AudioPlaylist> p, AudioPlaylistSource::AudioPlaylistSource (Session& s, const ID& orig, const std::string& name, boost::shared_ptr<AudioPlaylist> p,
uint32_t chn, sampleoffset_t begin, samplecnt_t len, Source::Flag flags) uint32_t chn, timepos_t const & begin, timepos_t const & len, Source::Flag flags)
: Source (s, DataType::AUDIO, name) : Source (s, DataType::AUDIO, name)
, PlaylistSource (s, orig, name, p, DataType::AUDIO, begin, len, flags) , PlaylistSource (s, orig, name, p, DataType::AUDIO, begin, len, flags)
, AudioSource (s, name) , AudioSource (s, name)
, _playlist_channel (chn) , _playlist_channel (chn)
{ {
AudioSource::_length = len; AudioSource::_length = timecnt_t (len);
ensure_buffers_for_level (_level, _session.sample_rate());
} }
AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node) AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node)
@ -70,7 +71,7 @@ AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node)
throw failed_constructor (); throw failed_constructor ();
} }
AudioSource::_length = _playlist_length; _length = timecnt_t (_playlist_length);
} }
AudioPlaylistSource::~AudioPlaylistSource () AudioPlaylistSource::~AudioPlaylistSource ()
@ -108,9 +109,9 @@ AudioPlaylistSource::set_state (const XMLNode& node, int version, bool with_desc
} }
} }
pair<samplepos_t,samplepos_t> extent = _playlist->get_extent(); pair<timepos_t,timepos_t> extent = _playlist->get_extent();
AudioSource::_length = extent.second - extent.first; AudioSource::_length = extent.first.distance (extent.second);
if (!node.get_property (X_("channel"), _playlist_channel)) { if (!node.get_property (X_("channel"), _playlist_channel)) {
throw failed_constructor (); throw failed_constructor ();
@ -130,8 +131,8 @@ AudioPlaylistSource::read_unlocked (Sample* dst, samplepos_t start, samplecnt_t
* is not supposed be part of our data. * is not supposed be part of our data.
*/ */
if (cnt > _playlist_length - start) { if (cnt > _playlist_length.samples() - start) {
to_read = _playlist_length - start; to_read = _playlist_length.samples() - start;
to_zero = cnt - to_read; to_zero = cnt - to_read;
} else { } else {
to_read = cnt; to_read = cnt;
@ -141,7 +142,7 @@ AudioPlaylistSource::read_unlocked (Sample* dst, samplepos_t start, samplecnt_t
boost::scoped_array<float> sbuf(new float[to_read]); boost::scoped_array<float> sbuf(new float[to_read]);
boost::scoped_array<gain_t> gbuf(new gain_t[to_read]); boost::scoped_array<gain_t> gbuf(new gain_t[to_read]);
boost::dynamic_pointer_cast<AudioPlaylist>(_playlist)->read (dst, sbuf.get(), gbuf.get(), start+_playlist_offset, to_read, _playlist_channel); boost::dynamic_pointer_cast<AudioPlaylist>(_playlist)->read (dst, sbuf.get(), gbuf.get(), timepos_t (start)+_playlist_offset, timecnt_t (to_read), _playlist_channel);
if (to_zero) { if (to_zero) {
memset (dst+to_read, 0, sizeof (Sample) * to_zero); memset (dst+to_read, 0, sizeof (Sample) * to_zero);

View file

@ -314,7 +314,7 @@ AudioRegionImporter::prepare_region ()
// create region and update XML // create region and update XML
boost::shared_ptr<Region> r = RegionFactory::create (source_list, xml_region); boost::shared_ptr<Region> r = RegionFactory::create (source_list, xml_region);
if (session.config.get_glue_new_regions_to_bars_and_beats ()) { if (session.config.get_glue_new_regions_to_bars_and_beats ()) {
r->set_position_lock_style (MusicTime); r->set_position_time_domain (Temporal::BeatTime);
} }
region.push_back (r); region.push_back (r);
if (*region.begin()) { if (*region.begin()) {

View file

@ -213,7 +213,7 @@ AudioTrack::export_stuff (BufferSet& buffers, samplepos_t start, samplecnt_t nfr
assert(buffers.count().n_audio() >= 1); assert(buffers.count().n_audio() >= 1);
assert ((samplecnt_t) buffers.get_audio(0).capacity() >= nframes); assert ((samplecnt_t) buffers.get_audio(0).capacity() >= nframes);
if (apl->read (buffers.get_audio(0).data(), mix_buffer.get(), gain_buffer.get(), start, nframes) != nframes) { if (apl->read (buffers.get_audio(0).data(), mix_buffer.get(), gain_buffer.get(), timepos_t (start), timecnt_t (nframes)) != nframes) {
return -1; return -1;
} }
@ -223,7 +223,7 @@ AudioTrack::export_stuff (BufferSet& buffers, samplepos_t start, samplecnt_t nfr
++bi; ++bi;
for ( ; bi != buffers.audio_end(); ++bi, ++n) { for ( ; bi != buffers.audio_end(); ++bi, ++n) {
if (n < _disk_reader->output_streams().n_audio()) { if (n < _disk_reader->output_streams().n_audio()) {
if (apl->read (bi->data(), mix_buffer.get(), gain_buffer.get(), start, nframes, n) != nframes) { if (apl->read (bi->data(), mix_buffer.get(), gain_buffer.get(), timepos_t (start), timecnt_t (nframes), n) != nframes) {
return -1; return -1;
} }
b = bi->data(); b = bi->data();
@ -402,14 +402,15 @@ AudioTrack::freeze_me (InterThreadInfo& itt)
PropertyList plist; PropertyList plist;
plist.add (Properties::start, 0); plist.add (Properties::start, 0);
plist.add (Properties::length, srcs[0]->length(srcs[0]->natural_position())); plist.add (Properties::length, srcs[0]->length());
plist.add (Properties::name, region_name); plist.add (Properties::name, region_name);
plist.add (Properties::whole_file, true); plist.add (Properties::whole_file, true);
boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist, false)); boost::shared_ptr<Region> region (RegionFactory::create (srcs, plist, false));
new_playlist->set_orig_track_id (id()); new_playlist->set_orig_track_id (id());
new_playlist->add_region (region, _session.current_start_sample()); #warning NUTEMPO fixme this probably should not use samples unconditionally
new_playlist->add_region (region, timepos_t (_session.current_start_sample()));
new_playlist->set_frozen (true); new_playlist->set_frozen (true);
region->set_locked (true); region->set_locked (true);

View file

@ -102,14 +102,14 @@ AudioAnalyser::reset ()
} }
int int
AudioAnalyser::analyse (const string& path, Readable* src, uint32_t channel) AudioAnalyser::analyse (const string& path, AudioReadable* src, uint32_t channel)
{ {
stringstream outss; stringstream outss;
Plugin::FeatureSet features; Plugin::FeatureSet features;
int ret = -1; int ret = -1;
bool done = false; bool done = false;
Sample* data = 0; Sample* data = 0;
samplecnt_t len = src->readable_length(); samplecnt_t len = src->readable_length_samples();
samplepos_t pos = 0; samplepos_t pos = 0;
float* bufs[1] = { 0 }; float* bufs[1] = { 0 };

View file

@ -85,10 +85,13 @@ namespace ARDOUR {
static void static void
reverse_curve (boost::shared_ptr<Evoral::ControlList> dst, boost::shared_ptr<const Evoral::ControlList> src) reverse_curve (boost::shared_ptr<Evoral::ControlList> dst, boost::shared_ptr<const Evoral::ControlList> src)
{ {
size_t len = src->when(false); const timepos_t end = src->when(false);
// TODO read-lock of src (!) // TODO read-lock of src (!)
for (Evoral::ControlList::const_reverse_iterator it = src->rbegin(); it!=src->rend(); it++) { for (Evoral::ControlList::const_reverse_iterator it = src->rbegin(); it!=src->rend(); it++) {
dst->fast_simple_add (len - (*it)->when, (*it)->value); /* ugh ... the double "distance" calls (with totally different
semantics ... horrible
*/
dst->fast_simple_add (timepos_t ((*it)->when.distance (end)), (*it)->value);
} }
} }
@ -108,17 +111,17 @@ static void
generate_db_fade (boost::shared_ptr<Evoral::ControlList> dst, double len, int num_steps, float dB_drop) generate_db_fade (boost::shared_ptr<Evoral::ControlList> dst, double len, int num_steps, float dB_drop)
{ {
dst->clear (); dst->clear ();
dst->fast_simple_add (0, 1); dst->fast_simple_add (timepos_t (Temporal::AudioTime), 1);
//generate a fade-out curve by successively applying a gain drop //generate a fade-out curve by successively applying a gain drop
float fade_speed = dB_to_coefficient(dB_drop / (float) num_steps); float fade_speed = dB_to_coefficient(dB_drop / (float) num_steps);
float coeff = GAIN_COEFF_UNITY; float coeff = GAIN_COEFF_UNITY;
for (int i = 1; i < (num_steps-1); i++) { for (int i = 1; i < (num_steps-1); i++) {
coeff *= fade_speed; coeff *= fade_speed;
dst->fast_simple_add (len*(double)i/(double)num_steps, coeff); dst->fast_simple_add (timepos_t (len*(double)i/(double)num_steps), coeff);
} }
dst->fast_simple_add (len, GAIN_COEFF_SMALL); dst->fast_simple_add (timepos_t (len), GAIN_COEFF_SMALL);
} }
static void static void
@ -194,6 +197,7 @@ AudioRegion::register_properties ()
add_property (_envelope); add_property (_envelope);
} }
#warning NUTEMPO QUESTION what time domains should be used here?
#define AUDIOREGION_STATE_DEFAULT \ #define AUDIOREGION_STATE_DEFAULT \
_envelope_active (Properties::envelope_active, false) \ _envelope_active (Properties::envelope_active, false) \
, _default_fade_in (Properties::default_fade_in, true) \ , _default_fade_in (Properties::default_fade_in, true) \
@ -201,10 +205,10 @@ AudioRegion::register_properties ()
, _fade_in_active (Properties::fade_in_active, true) \ , _fade_in_active (Properties::fade_in_active, true) \
, _fade_out_active (Properties::fade_out_active, true) \ , _fade_out_active (Properties::fade_out_active, true) \
, _scale_amplitude (Properties::scale_amplitude, 1.0) \ , _scale_amplitude (Properties::scale_amplitude, 1.0) \
, _fade_in (Properties::fade_in, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation)))) \ , _fade_in (Properties::fade_in, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation), Temporal::AudioTime))) \
, _inverse_fade_in (Properties::inverse_fade_in, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation)))) \ , _inverse_fade_in (Properties::inverse_fade_in, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeInAutomation), Temporal::AudioTime))) \
, _fade_out (Properties::fade_out, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeOutAutomation)))) \ , _fade_out (Properties::fade_out, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeOutAutomation), Temporal::AudioTime))) \
, _inverse_fade_out (Properties::inverse_fade_out, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeOutAutomation)))) , _inverse_fade_out (Properties::inverse_fade_out, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (FadeOutAutomation), Temporal::AudioTime)))
#define AUDIOREGION_COPY_STATE(other) \ #define AUDIOREGION_COPY_STATE(other) \
_envelope_active (Properties::envelope_active, other->_envelope_active) \ _envelope_active (Properties::envelope_active, other->_envelope_active) \
@ -238,7 +242,7 @@ AudioRegion::init ()
AudioRegion::AudioRegion (Session& s, timecnt_t const & start, timecnt_t const & len, std::string name) AudioRegion::AudioRegion (Session& s, timecnt_t const & start, timecnt_t const & len, std::string name)
: Region (s, start, len, name, DataType::AUDIO) : Region (s, start, len, name, DataType::AUDIO)
, AUDIOREGION_STATE_DEFAULT , AUDIOREGION_STATE_DEFAULT
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter(EnvelopeAutomation)))) , _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter(EnvelopeAutomation), Temporal::AudioTime)))
, _automatable (s) , _automatable (s)
, _fade_in_suspended (0) , _fade_in_suspended (0)
, _fade_out_suspended (0) , _fade_out_suspended (0)
@ -251,7 +255,7 @@ AudioRegion::AudioRegion (Session& s, timecnt_t const & start, timecnt_t const
AudioRegion::AudioRegion (const SourceList& srcs) AudioRegion::AudioRegion (const SourceList& srcs)
: Region (srcs) : Region (srcs)
, AUDIOREGION_STATE_DEFAULT , AUDIOREGION_STATE_DEFAULT
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter(EnvelopeAutomation)))) , _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter(EnvelopeAutomation), Temporal::AudioTime)))
, _automatable(srcs[0]->session()) , _automatable(srcs[0]->session())
, _fade_in_suspended (0) , _fade_in_suspended (0)
, _fade_out_suspended (0) , _fade_out_suspended (0)
@ -266,7 +270,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other)
/* As far as I can see, the _envelope's times are relative to region position, and have nothing /* As far as I can see, the _envelope's times are relative to region position, and have nothing
* to do with sources (and hence _start). So when we copy the envelope, we just use the supplied offset. * to do with sources (and hence _start). So when we copy the envelope, we just use the supplied offset.
*/ */
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (*other->_envelope.val(), 0, other->_length))) , _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (*other->_envelope.val(), timepos_t (Temporal::AudioTime), timepos_t (other->_length))))
, _automatable (other->session()) , _automatable (other->session())
, _fade_in_suspended (0) , _fade_in_suspended (0)
, _fade_out_suspended (0) , _fade_out_suspended (0)
@ -288,7 +292,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, timecnt_t
/* As far as I can see, the _envelope's times are relative to region position, and have nothing /* As far as I can see, the _envelope's times are relative to region position, and have nothing
to do with sources (and hence _start). So when we copy the envelope, we just use the supplied offset. to do with sources (and hence _start). So when we copy the envelope, we just use the supplied offset.
*/ */
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (*other->_envelope.val(), offset.sample, other->_length))) , _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList (*other->_envelope.val(), timepos_t (offset.samples()), timepos_t (other->_length))))
, _automatable (other->session()) , _automatable (other->session())
, _fade_in_suspended (0) , _fade_in_suspended (0)
, _fade_out_suspended (0) , _fade_out_suspended (0)
@ -326,7 +330,7 @@ AudioRegion::AudioRegion (boost::shared_ptr<const AudioRegion> other, const Sour
AudioRegion::AudioRegion (SourceList& srcs) AudioRegion::AudioRegion (SourceList& srcs)
: Region (srcs) : Region (srcs)
, AUDIOREGION_STATE_DEFAULT , AUDIOREGION_STATE_DEFAULT
, _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList(Evoral::Parameter(EnvelopeAutomation)))) , _envelope (Properties::envelope, boost::shared_ptr<AutomationList> (new AutomationList(Evoral::Parameter(EnvelopeAutomation), Temporal::AudioTime)))
, _automatable(srcs[0]->session()) , _automatable(srcs[0]->session())
, _fade_in_suspended (0) , _fade_in_suspended (0)
, _fade_out_suspended (0) , _fade_out_suspended (0)
@ -368,7 +372,7 @@ AudioRegion::post_set (const PropertyChange& /*ignored*/)
} }
/* If _length changed, adjust our gain envelope accordingly */ /* If _length changed, adjust our gain envelope accordingly */
_envelope->truncate_end (_length); _envelope->truncate_end (timepos_t (_length.val()));
} }
void void
@ -454,7 +458,7 @@ samplecnt_t
AudioRegion::read (Sample* buf, samplepos_t pos, samplecnt_t cnt, int channel) const AudioRegion::read (Sample* buf, samplepos_t pos, samplecnt_t cnt, int channel) const
{ {
/* raw read, no fades, no gain, nada */ /* raw read, no fades, no gain, nada */
return read_from_sources (_sources, _length, buf, _position + pos, cnt, channel); return read_from_sources (_sources, _length.val().samples(), buf, _position.val().samples() + pos, cnt, channel);
} }
samplecnt_t samplecnt_t
@ -464,10 +468,7 @@ AudioRegion::master_read_at (Sample *buf, Sample* /*mixdown_buffer*/, float* /*g
/* do not read gain/scaling/fades and do not count this disk i/o in statistics */ /* do not read gain/scaling/fades and do not count this disk i/o in statistics */
assert (cnt >= 0); assert (cnt >= 0);
return read_from_sources ( return read_from_sources (_master_sources, _master_sources.front()->length ().samples(), buf, position, cnt, chan_n);
_master_sources, _master_sources.front()->length (_master_sources.front()->natural_position()),
buf, position, cnt, chan_n
);
} }
/** @param buf Buffer to mix data into. /** @param buf Buffer to mix data into.
@ -500,15 +501,17 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
/* WORK OUT WHERE TO GET DATA FROM */ /* WORK OUT WHERE TO GET DATA FROM */
samplecnt_t to_read; samplecnt_t to_read;
const samplepos_t psamples = _position.val().samples();
const samplecnt_t lsamples = _length.val().samples();
assert (position >= _position); assert (position >= psamples);
sampleoffset_t const internal_offset = position - _position; sampleoffset_t const internal_offset = position - psamples;
if (internal_offset >= _length) { if (internal_offset >= lsamples) {
return 0; /* read nothing */ return 0; /* read nothing */
} }
if ((to_read = min (cnt, _length - internal_offset)) == 0) { if ((to_read = min (cnt, lsamples - internal_offset)) == 0) {
return 0; /* read nothing */ return 0; /* read nothing */
} }
@ -516,7 +519,7 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
if (!pl){ if (!pl){
return 0; return 0;
} }
/* COMPUTE DETAILS OF ANY FADES INVOLVED IN THIS READ */ /* COMPUTE DETAILS OF ANY FADES INVOLVED IN THIS READ */
/* Amount (length) of fade in that we are dealing with in this read */ /* Amount (length) of fade in that we are dealing with in this read */
@ -536,7 +539,7 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
if (_fade_in_active && _session.config.get_use_region_fades()) { if (_fade_in_active && _session.config.get_use_region_fades()) {
samplecnt_t fade_in_length = (samplecnt_t) _fade_in->when(false); samplecnt_t fade_in_length = _fade_in->when(false).samples();
/* see if this read is within the fade in */ /* see if this read is within the fade in */
@ -568,8 +571,8 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
* *
*/ */
fade_interval_start = max (internal_offset, _length - samplecnt_t (_fade_out->when(false))); fade_interval_start = max (internal_offset, lsamples - _fade_out->when(false).samples());
samplecnt_t fade_interval_end = min(internal_offset + to_read, _length.val()); samplecnt_t fade_interval_end = min(internal_offset + to_read, lsamples);
if (fade_interval_end > fade_interval_start) { if (fade_interval_end > fade_interval_start) {
/* (part of the) the fade out is in this buffer */ /* (part of the) the fade out is in this buffer */
@ -584,14 +587,14 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
may need to mix with the existing data. may need to mix with the existing data.
*/ */
if (read_from_sources (_sources, _length, mixdown_buffer, position, to_read, chan_n) != to_read) { if (read_from_sources (_sources, lsamples, mixdown_buffer, psamples, to_read, chan_n) != to_read) {
return 0; return 0;
} }
/* APPLY REGULAR GAIN CURVES AND SCALING TO mixdown_buffer */ /* APPLY REGULAR GAIN CURVES AND SCALING TO mixdown_buffer */
if (envelope_active()) { if (envelope_active()) {
_envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read); _envelope->curve().get_vector (timepos_t (internal_offset), timepos_t (internal_offset + to_read), gain_buffer, to_read);
if (_scale_amplitude != 1.0f) { if (_scale_amplitude != 1.0f) {
for (samplecnt_t n = 0; n < to_read; ++n) { for (samplecnt_t n = 0; n < to_read; ++n) {
@ -612,7 +615,7 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
* "buf" contains data from lower regions already. So this operation * "buf" contains data from lower regions already. So this operation
* fades out the existing material. * fades out the existing material.
*/ */
bool is_opaque = opaque(); bool is_opaque = opaque();
if (fade_in_limit != 0) { if (fade_in_limit != 0) {
@ -624,7 +627,7 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
* power), so we have to fetch it. * power), so we have to fetch it.
*/ */
_inverse_fade_in->curve().get_vector (internal_offset, internal_offset + fade_in_limit, gain_buffer, fade_in_limit); _inverse_fade_in->curve().get_vector (timepos_t (internal_offset), timepos_t (internal_offset + fade_in_limit), gain_buffer, fade_in_limit);
/* Fade the data from lower layers out */ /* Fade the data from lower layers out */
for (samplecnt_t n = 0; n < fade_in_limit; ++n) { for (samplecnt_t n = 0; n < fade_in_limit; ++n) {
@ -633,7 +636,7 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
/* refill gain buffer with the fade in */ /* refill gain buffer with the fade in */
_fade_in->curve().get_vector (internal_offset, internal_offset + fade_in_limit, gain_buffer, fade_in_limit); _fade_in->curve().get_vector (timepos_t (internal_offset), timepos_t (internal_offset + fade_in_limit), gain_buffer, fade_in_limit);
} else { } else {
@ -641,14 +644,14 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
* in) for the fade out of lower layers * in) for the fade out of lower layers
*/ */
_fade_in->curve().get_vector (internal_offset, internal_offset + fade_in_limit, gain_buffer, fade_in_limit); _fade_in->curve().get_vector (timepos_t (internal_offset), timepos_t (internal_offset + fade_in_limit), gain_buffer, fade_in_limit);
for (samplecnt_t n = 0; n < fade_in_limit; ++n) { for (samplecnt_t n = 0; n < fade_in_limit; ++n) {
buf[n] *= 1 - gain_buffer[n]; buf[n] *= 1 - gain_buffer[n];
} }
} }
} else { } else {
_fade_in->curve().get_vector (internal_offset, internal_offset + fade_in_limit, gain_buffer, fade_in_limit); _fade_in->curve().get_vector (timepos_t (internal_offset), timepos_t (internal_offset + fade_in_limit), gain_buffer, fade_in_limit);
} }
/* Mix our newly-read data in, with the fade */ /* Mix our newly-read data in, with the fade */
@ -659,12 +662,12 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
if (fade_out_limit != 0) { if (fade_out_limit != 0) {
samplecnt_t const curve_offset = fade_interval_start - (_length - _fade_out->when(false)); samplecnt_t const curve_offset = fade_interval_start - _fade_out->when(false).distance (timepos_t (_length)).samples();
if (is_opaque) { if (is_opaque) {
if (_inverse_fade_out) { if (_inverse_fade_out) {
_inverse_fade_out->curve().get_vector (curve_offset, curve_offset + fade_out_limit, gain_buffer, fade_out_limit); _inverse_fade_out->curve().get_vector (timepos_t (curve_offset), timepos_t (curve_offset + fade_out_limit), gain_buffer, fade_out_limit);
/* Fade the data from lower levels in */ /* Fade the data from lower levels in */
for (samplecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) { for (samplecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) {
@ -673,7 +676,7 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
/* fetch the actual fade out */ /* fetch the actual fade out */
_fade_out->curve().get_vector (curve_offset, curve_offset + fade_out_limit, gain_buffer, fade_out_limit); _fade_out->curve().get_vector (timepos_t (curve_offset), timepos_t (curve_offset + fade_out_limit), gain_buffer, fade_out_limit);
} else { } else {
@ -682,14 +685,14 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
* out) for the fade in of lower layers * out) for the fade in of lower layers
*/ */
_fade_out->curve().get_vector (curve_offset, curve_offset + fade_out_limit, gain_buffer, fade_out_limit); _fade_out->curve().get_vector (timepos_t (curve_offset), timepos_t (curve_offset + fade_out_limit), gain_buffer, fade_out_limit);
for (samplecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) { for (samplecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) {
buf[m] *= 1 - gain_buffer[n]; buf[m] *= 1 - gain_buffer[n];
} }
} }
} else { } else {
_fade_out->curve().get_vector (curve_offset, curve_offset + fade_out_limit, gain_buffer, fade_out_limit); _fade_out->curve().get_vector (timepos_t (curve_offset), timepos_t (curve_offset + fade_out_limit), gain_buffer, fade_out_limit);
} }
/* Mix our newly-read data with whatever was already there, /* Mix our newly-read data with whatever was already there,
@ -731,7 +734,7 @@ AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
samplecnt_t samplecnt_t
AudioRegion::read_from_sources (SourceList const & srcs, samplecnt_t limit, Sample* buf, samplepos_t position, samplecnt_t cnt, uint32_t chan_n) const AudioRegion::read_from_sources (SourceList const & srcs, samplecnt_t limit, Sample* buf, samplepos_t position, samplecnt_t cnt, uint32_t chan_n) const
{ {
sampleoffset_t const internal_offset = position - _position; sampleoffset_t const internal_offset = position - _position.val().samples();
if (internal_offset >= limit) { if (internal_offset >= limit) {
return 0; return 0;
} }
@ -744,7 +747,7 @@ AudioRegion::read_from_sources (SourceList const & srcs, samplecnt_t limit, Samp
if (chan_n < n_channels()) { if (chan_n < n_channels()) {
boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[chan_n]); boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[chan_n]);
if (src->read (buf, _start + internal_offset, to_read) != to_read) { if (src->read (buf, _start.val().samples() + internal_offset, to_read) != to_read) {
return 0; /* "read nothing" */ return 0; /* "read nothing" */
} }
@ -761,7 +764,7 @@ AudioRegion::read_from_sources (SourceList const & srcs, samplecnt_t limit, Samp
uint32_t channel = chan_n % n_channels(); uint32_t channel = chan_n % n_channels();
boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[channel]); boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[channel]);
if (src->read (buf, _start + internal_offset, to_read) != to_read) { if (src->read (buf, _start.val().samples() + internal_offset, to_read) != to_read) {
return 0; /* "read nothing" */ return 0; /* "read nothing" */
} }
@ -801,7 +804,7 @@ AudioRegion::state ()
if (_envelope->size() == 2 && if (_envelope->size() == 2 &&
_envelope->front()->value == GAIN_COEFF_UNITY && _envelope->front()->value == GAIN_COEFF_UNITY &&
_envelope->back()->value==GAIN_COEFF_UNITY) { _envelope->back()->value==GAIN_COEFF_UNITY) {
if (_envelope->front()->when == 0 && _envelope->back()->when == _length) { if (_envelope->front()->when == 0 && _envelope->back()->when == timepos_t (_length)) {
default_env = true; default_env = true;
} }
} }
@ -886,7 +889,7 @@ AudioRegion::_set_state (const XMLNode& node, int version, PropertyChange& what_
set_default_envelope (); set_default_envelope ();
} }
_envelope->truncate_end (_length); _envelope->truncate_end (timepos_t (_length));
} else if (child->name() == "FadeIn") { } else if (child->name() == "FadeIn") {
@ -966,20 +969,20 @@ AudioRegion::fade_range (samplepos_t start, samplepos_t end)
{ {
samplepos_t s, e; samplepos_t s, e;
switch (coverage (start, end)) { switch (coverage (timepos_t (start), timepos_t (end))) {
case Evoral::OverlapStart: case Temporal::OverlapStart:
trim_front(start); trim_front (timepos_t (start));
s = _position; s = _position.val().samples();
e = end; e = end;
set_fade_in (FadeConstantPower, e - s); set_fade_in (FadeConstantPower, e - s);
break; break;
case Evoral::OverlapEnd: case Temporal::OverlapEnd:
trim_end(end); trim_end(timepos_t (end));
s = start; s = start;
e = _position + _length; e = (_position.val() + timepos_t (_length)).samples();
set_fade_out (FadeConstantPower, e - s); set_fade_out (FadeConstantPower, e - s);
break; break;
case Evoral::OverlapInternal: case Temporal::OverlapInternal:
/* needs addressing, perhaps. Difficult to do if we can't /* needs addressing, perhaps. Difficult to do if we can't
* control one edge of the fade relative to the relevant edge * control one edge of the fade relative to the relevant edge
* of the region, which we cannot - fades are currently assumed * of the region, which we cannot - fades are currently assumed
@ -994,13 +997,13 @@ AudioRegion::fade_range (samplepos_t start, samplepos_t end)
void void
AudioRegion::set_fade_in_shape (FadeShape shape) AudioRegion::set_fade_in_shape (FadeShape shape)
{ {
set_fade_in (shape, (samplecnt_t) _fade_in->when(false)); set_fade_in (shape, _fade_in->when(false).samples());
} }
void void
AudioRegion::set_fade_out_shape (FadeShape shape) AudioRegion::set_fade_out_shape (FadeShape shape)
{ {
set_fade_out (shape, (samplecnt_t) _fade_out->when(false)); set_fade_out (shape, _fade_out->when(false).samples());
} }
void void
@ -1018,9 +1021,9 @@ void
AudioRegion::set_fade_in (FadeShape shape, samplecnt_t len) AudioRegion::set_fade_in (FadeShape shape, samplecnt_t len)
{ {
const ARDOUR::ParameterDescriptor desc(FadeInAutomation); const ARDOUR::ParameterDescriptor desc(FadeInAutomation);
boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeInAutomation, desc)); boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeInAutomation, desc, Temporal::AudioTime));
boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (FadeInAutomation, desc)); boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (FadeInAutomation, desc, Temporal::AudioTime));
boost::shared_ptr<Evoral::ControlList> c3 (new Evoral::ControlList (FadeInAutomation, desc)); boost::shared_ptr<Evoral::ControlList> c3 (new Evoral::ControlList (FadeInAutomation, desc, Temporal::AudioTime));
_fade_in->freeze (); _fade_in->freeze ();
_fade_in->clear (); _fade_in->clear ();
@ -1030,8 +1033,8 @@ AudioRegion::set_fade_in (FadeShape shape, samplecnt_t len)
switch (shape) { switch (shape) {
case FadeLinear: case FadeLinear:
_fade_in->fast_simple_add (0.0, GAIN_COEFF_SMALL); _fade_in->fast_simple_add (timepos_t (Temporal::AudioTime), GAIN_COEFF_SMALL);
_fade_in->fast_simple_add (len, GAIN_COEFF_UNITY); _fade_in->fast_simple_add (timepos_t (len), GAIN_COEFF_UNITY);
reverse_curve (_inverse_fade_in.val(), _fade_in.val()); reverse_curve (_inverse_fade_in.val(), _fade_in.val());
break; break;
@ -1052,26 +1055,26 @@ AudioRegion::set_fade_in (FadeShape shape, samplecnt_t len)
break; break;
case FadeConstantPower: case FadeConstantPower:
_fade_in->fast_simple_add (0.0, GAIN_COEFF_SMALL); _fade_in->fast_simple_add (timepos_t (Temporal::AudioTime), GAIN_COEFF_SMALL);
for (int i = 1; i < num_steps; ++i) { for (int i = 1; i < num_steps; ++i) {
const float dist = i / (num_steps + 1.f); const float dist = i / (num_steps + 1.f);
_fade_in->fast_simple_add (len * dist, sin (dist * M_PI / 2.0)); _fade_in->fast_simple_add (timepos_t (len * dist), sin (dist * M_PI / 2.0));
} }
_fade_in->fast_simple_add (len, GAIN_COEFF_UNITY); _fade_in->fast_simple_add (timepos_t (len), GAIN_COEFF_UNITY);
reverse_curve (_inverse_fade_in.val(), _fade_in.val()); reverse_curve (_inverse_fade_in.val(), _fade_in.val());
break; break;
case FadeSymmetric: case FadeSymmetric:
//start with a nearly linear cuve //start with a nearly linear cuve
_fade_in->fast_simple_add (0, 1); _fade_in->fast_simple_add (timepos_t (Temporal::AudioTime), 1);
_fade_in->fast_simple_add (0.5 * len, 0.6); _fade_in->fast_simple_add (timepos_t (0.5 * len), 0.6);
//now generate a fade-out curve by successively applying a gain drop //now generate a fade-out curve by successively applying a gain drop
const double breakpoint = 0.7; //linear for first 70% const double breakpoint = 0.7; //linear for first 70%
for (int i = 2; i < 9; ++i) { for (int i = 2; i < 9; ++i) {
const float coeff = (1.f - breakpoint) * powf (0.5, i); const float coeff = (1.f - breakpoint) * powf (0.5, i);
_fade_in->fast_simple_add (len * (breakpoint + ((GAIN_COEFF_UNITY - breakpoint) * (double)i / 9.0)), coeff); _fade_in->fast_simple_add (timepos_t (len * (breakpoint + ((GAIN_COEFF_UNITY - breakpoint) * (double)i / 9.0))), coeff);
} }
_fade_in->fast_simple_add (len, GAIN_COEFF_SMALL); _fade_in->fast_simple_add (timepos_t (len), GAIN_COEFF_SMALL);
reverse_curve (c3, _fade_in.val()); reverse_curve (c3, _fade_in.val());
_fade_in->copy_events (*c3); _fade_in->copy_events (*c3);
reverse_curve (_inverse_fade_in.val(), _fade_in.val()); reverse_curve (_inverse_fade_in.val(), _fade_in.val());
@ -1101,8 +1104,8 @@ void
AudioRegion::set_fade_out (FadeShape shape, samplecnt_t len) AudioRegion::set_fade_out (FadeShape shape, samplecnt_t len)
{ {
const ARDOUR::ParameterDescriptor desc(FadeOutAutomation); const ARDOUR::ParameterDescriptor desc(FadeOutAutomation);
boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeOutAutomation, desc)); boost::shared_ptr<Evoral::ControlList> c1 (new Evoral::ControlList (FadeOutAutomation, desc, Temporal::AudioTime));
boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (FadeOutAutomation, desc)); boost::shared_ptr<Evoral::ControlList> c2 (new Evoral::ControlList (FadeOutAutomation, desc, Temporal::AudioTime));
_fade_out->freeze (); _fade_out->freeze ();
_fade_out->clear (); _fade_out->clear ();
@ -1112,8 +1115,8 @@ AudioRegion::set_fade_out (FadeShape shape, samplecnt_t len)
switch (shape) { switch (shape) {
case FadeLinear: case FadeLinear:
_fade_out->fast_simple_add (0.0, GAIN_COEFF_UNITY); _fade_out->fast_simple_add (timepos_t (Temporal::AudioTime), GAIN_COEFF_UNITY);
_fade_out->fast_simple_add (len, GAIN_COEFF_SMALL); _fade_out->fast_simple_add (timepos_t (len), GAIN_COEFF_SMALL);
reverse_curve (_inverse_fade_out.val(), _fade_out.val()); reverse_curve (_inverse_fade_out.val(), _fade_out.val());
break; break;
@ -1132,26 +1135,26 @@ AudioRegion::set_fade_out (FadeShape shape, samplecnt_t len)
case FadeConstantPower: case FadeConstantPower:
//constant-power fades use a sin/cos relationship //constant-power fades use a sin/cos relationship
//the cutoff is abrupt but it has the benefit of being symmetrical //the cutoff is abrupt but it has the benefit of being symmetrical
_fade_out->fast_simple_add (0.0, GAIN_COEFF_UNITY); _fade_out->fast_simple_add (timepos_t (Temporal::AudioTime), GAIN_COEFF_UNITY);
for (int i = 1; i < num_steps; ++i) { for (int i = 1; i < num_steps; ++i) {
const float dist = i / (num_steps + 1.f); const float dist = i / (num_steps + 1.f);
_fade_out->fast_simple_add (len * dist, cos (dist * M_PI / 2.0)); _fade_out->fast_simple_add (timepos_t (len * dist), cos (dist * M_PI / 2.0));
} }
_fade_out->fast_simple_add (len, GAIN_COEFF_SMALL); _fade_out->fast_simple_add (timepos_t (len), GAIN_COEFF_SMALL);
reverse_curve (_inverse_fade_out.val(), _fade_out.val()); reverse_curve (_inverse_fade_out.val(), _fade_out.val());
break; break;
case FadeSymmetric: case FadeSymmetric:
//start with a nearly linear cuve //start with a nearly linear cuve
_fade_out->fast_simple_add (0, 1); _fade_out->fast_simple_add (timepos_t (Temporal::AudioTime), 1);
_fade_out->fast_simple_add (0.5 * len, 0.6); _fade_out->fast_simple_add (timepos_t (0.5 * len), 0.6);
//now generate a fade-out curve by successively applying a gain drop //now generate a fade-out curve by successively applying a gain drop
const double breakpoint = 0.7; //linear for first 70% const double breakpoint = 0.7; //linear for first 70%
for (int i = 2; i < 9; ++i) { for (int i = 2; i < 9; ++i) {
const float coeff = (1.f - breakpoint) * powf (0.5, i); const float coeff = (1.f - breakpoint) * powf (0.5, i);
_fade_out->fast_simple_add (len * (breakpoint + ((GAIN_COEFF_UNITY - breakpoint) * (double)i / 9.0)), coeff); _fade_out->fast_simple_add (timepos_t (len * (breakpoint + ((GAIN_COEFF_UNITY - breakpoint) * (double)i / 9.0))), coeff);
} }
_fade_out->fast_simple_add (len, GAIN_COEFF_SMALL); _fade_out->fast_simple_add (timepos_t (len), GAIN_COEFF_SMALL);
reverse_curve (_inverse_fade_out.val(), _fade_out.val()); reverse_curve (_inverse_fade_out.val(), _fade_out.val());
break; break;
} }
@ -1167,19 +1170,19 @@ AudioRegion::set_fade_out (FadeShape shape, samplecnt_t len)
void void
AudioRegion::set_fade_in_length (samplecnt_t len) AudioRegion::set_fade_in_length (samplecnt_t len)
{ {
if (len > _length) { if (len > length_samples()) {
len = _length - 1; len = length_samples() - 1;
} }
if (len < 64) { if (len < 64) {
len = 64; len = 64;
} }
bool changed = _fade_in->extend_to (len); bool changed = _fade_in->extend_to (timepos_t (len));
if (changed) { if (changed) {
if (_inverse_fade_in) { if (_inverse_fade_in) {
_inverse_fade_in->extend_to (len); _inverse_fade_in->extend_to (timepos_t (len));
} }
_default_fade_in = false; _default_fade_in = false;
@ -1190,20 +1193,20 @@ AudioRegion::set_fade_in_length (samplecnt_t len)
void void
AudioRegion::set_fade_out_length (samplecnt_t len) AudioRegion::set_fade_out_length (samplecnt_t len)
{ {
if (len > _length) { if (len > length_samples()) {
len = _length - 1; len = length_samples() - 1;
} }
if (len < 64) { if (len < 64) {
len = 64; len = 64;
} }
bool changed = _fade_out->extend_to (len); bool changed = _fade_out->extend_to (timepos_t (len));
if (changed) { if (changed) {
if (_inverse_fade_out) { if (_inverse_fade_out) {
_inverse_fade_out->extend_to (len); _inverse_fade_out->extend_to (timepos_t (len));
} }
_default_fade_out = false; _default_fade_out = false;
@ -1270,8 +1273,8 @@ AudioRegion::set_default_envelope ()
{ {
_envelope->freeze (); _envelope->freeze ();
_envelope->clear (); _envelope->clear ();
_envelope->fast_simple_add (0, GAIN_COEFF_UNITY); _envelope->fast_simple_add (timepos_t (Temporal::AudioTime), GAIN_COEFF_UNITY);
_envelope->fast_simple_add (_length, GAIN_COEFF_UNITY); _envelope->fast_simple_add (timepos_t (_length), GAIN_COEFF_UNITY);
_envelope->thaw (); _envelope->thaw ();
} }
@ -1283,7 +1286,7 @@ AudioRegion::recompute_at_end ()
*/ */
_envelope->freeze (); _envelope->freeze ();
_envelope->truncate_end (_length); _envelope->truncate_end (timepos_t (_length));
_envelope->thaw (); _envelope->thaw ();
suspend_property_changes(); suspend_property_changes();
@ -1292,12 +1295,12 @@ AudioRegion::recompute_at_end ()
set_default_fade_out (); set_default_fade_out ();
_left_of_split = false; _left_of_split = false;
} else if (_fade_out->when(false) > _length) { } else if (_fade_out->when(false) > _length) {
_fade_out->extend_to (_length); _fade_out->extend_to (timepos_t (_length));
send_change (PropertyChange (Properties::fade_out)); send_change (PropertyChange (Properties::fade_out));
} }
if (_fade_in->when(false) > _length) { if (_fade_in->when(false) > _length) {
_fade_in->extend_to (_length); _fade_in->extend_to (timepos_t (_length));
send_change (PropertyChange (Properties::fade_in)); send_change (PropertyChange (Properties::fade_in));
} }
@ -1317,12 +1320,12 @@ AudioRegion::recompute_at_start ()
set_default_fade_in (); set_default_fade_in ();
_right_of_split = false; _right_of_split = false;
} else if (_fade_in->when(false) > _length) { } else if (_fade_in->when(false) > _length) {
_fade_in->extend_to (_length); _fade_in->extend_to (timepos_t (_length));
send_change (PropertyChange (Properties::fade_in)); send_change (PropertyChange (Properties::fade_in));
} }
if (_fade_out->when(false) > _length) { if (_fade_out->when(false) > _length) {
_fade_out->extend_to (_length); _fade_out->extend_to (timepos_t (_length));
send_change (PropertyChange (Properties::fade_out)); send_change (PropertyChange (Properties::fade_out));
} }
@ -1396,8 +1399,8 @@ AudioRegion::set_scale_amplitude (gain_t g)
double double
AudioRegion::maximum_amplitude (Progress* p) const AudioRegion::maximum_amplitude (Progress* p) const
{ {
samplepos_t fpos = _start; samplepos_t fpos = start_sample();;
samplepos_t const fend = _start + _length; samplepos_t const fend = start_sample() + length_samples();
double maxamp = 0; double maxamp = 0;
samplecnt_t const blocksize = 64 * 1024; samplecnt_t const blocksize = 64 * 1024;
@ -1422,7 +1425,7 @@ AudioRegion::maximum_amplitude (Progress* p) const
fpos += to_read; fpos += to_read;
if (p) { if (p) {
p->set_progress (float (fpos - _start) / _length); p->set_progress (float (fpos - start_sample()) / length_samples());
if (p->cancelled ()) { if (p->cancelled ()) {
return -1; return -1;
} }
@ -1435,8 +1438,8 @@ AudioRegion::maximum_amplitude (Progress* p) const
double double
AudioRegion::rms (Progress* p) const AudioRegion::rms (Progress* p) const
{ {
samplepos_t fpos = _start; samplepos_t fpos = start_sample();
samplepos_t const fend = _start + _length; samplepos_t const fend = start_sample() + length_samples();
uint32_t const n_chan = n_channels (); uint32_t const n_chan = n_channels ();
double rms = 0; double rms = 0;
@ -1462,7 +1465,7 @@ AudioRegion::rms (Progress* p) const
total += to_read; total += to_read;
fpos += to_read; fpos += to_read;
if (p) { if (p) {
p->set_progress (float (fpos - _start) / _length); p->set_progress (float (fpos - start_sample()) / length_samples());
if (p->cancelled ()) { if (p->cancelled ()) {
return -1; return -1;
} }
@ -1633,13 +1636,13 @@ AudioRegion::add_transient (samplepos_t where)
if (where < first_sample () || where >= last_sample ()) { if (where < first_sample () || where >= last_sample ()) {
return; return;
} }
where -= _position; where -= position_sample();
if (!_valid_transients) { if (!_valid_transients) {
_transient_user_start = _start; _transient_user_start = start_sample();
_valid_transients = true; _valid_transients = true;
} }
sampleoffset_t offset = _transient_user_start - _start; sampleoffset_t offset = _transient_user_start - start_sample();;
if (where < offset) { if (where < offset) {
if (offset <= 0) { if (offset <= 0) {
@ -1663,16 +1666,16 @@ AudioRegion::update_transient (samplepos_t old_position, samplepos_t new_positio
{ {
bool changed = false; bool changed = false;
if (!_onsets.empty ()) { if (!_onsets.empty ()) {
const samplepos_t p = old_position - _position; const samplepos_t p = old_position - position_sample();
AnalysisFeatureList::iterator x = std::find (_onsets.begin (), _onsets.end (), p); AnalysisFeatureList::iterator x = std::find (_onsets.begin (), _onsets.end (), p);
if (x != _transients.end ()) { if (x != _transients.end ()) {
(*x) = new_position - _position; (*x) = new_position - position_sample();
changed = true; changed = true;
} }
} }
if (_valid_transients) { if (_valid_transients) {
const sampleoffset_t offset = _position + _transient_user_start - _start; const sampleoffset_t offset = position_sample() + _transient_user_start - start_sample();
const samplepos_t p = old_position - offset; const samplepos_t p = old_position - offset;
AnalysisFeatureList::iterator x = std::find (_user_transients.begin (), _user_transients.end (), p); AnalysisFeatureList::iterator x = std::find (_user_transients.begin (), _user_transients.end (), p);
if (x != _transients.end ()) { if (x != _transients.end ()) {
@ -1691,7 +1694,7 @@ AudioRegion::remove_transient (samplepos_t where)
{ {
bool changed = false; bool changed = false;
if (!_onsets.empty ()) { if (!_onsets.empty ()) {
const samplepos_t p = where - _position; const samplepos_t p = where - position_sample();
AnalysisFeatureList::iterator i = std::find (_onsets.begin (), _onsets.end (), p); AnalysisFeatureList::iterator i = std::find (_onsets.begin (), _onsets.end (), p);
if (i != _onsets.end ()) { if (i != _onsets.end ()) {
_onsets.erase (i); _onsets.erase (i);
@ -1700,7 +1703,7 @@ AudioRegion::remove_transient (samplepos_t where)
} }
if (_valid_transients) { if (_valid_transients) {
const samplepos_t p = where - (_position + _transient_user_start - _start); const samplepos_t p = where - (position_sample() + _transient_user_start - start_sample());
AnalysisFeatureList::iterator i = std::find (_user_transients.begin (), _user_transients.end (), p); AnalysisFeatureList::iterator i = std::find (_user_transients.begin (), _user_transients.end (), p);
if (i != _user_transients.end ()) { if (i != _user_transients.end ()) {
_user_transients.erase (i); _user_transients.erase (i);
@ -1751,11 +1754,11 @@ AudioRegion::build_transients ()
/* find the set of transients within the bounds of this region */ /* find the set of transients within the bounds of this region */
AnalysisFeatureList::iterator low = lower_bound ((*s)->transients.begin(), AnalysisFeatureList::iterator low = lower_bound ((*s)->transients.begin(),
(*s)->transients.end(), (*s)->transients.end(),
_start); start_sample());
AnalysisFeatureList::iterator high = upper_bound ((*s)->transients.begin(), AnalysisFeatureList::iterator high = upper_bound ((*s)->transients.begin(),
(*s)->transients.end(), (*s)->transients.end(),
_start + _length); start_sample() + length_samples());
/* and add them */ /* and add them */
_transients.insert (_transients.end(), low, high); _transients.insert (_transients.end(), low, high);
@ -1765,11 +1768,11 @@ AudioRegion::build_transients ()
/* translate all transients to current position */ /* translate all transients to current position */
for (AnalysisFeatureList::iterator x = _transients.begin(); x != _transients.end(); ++x) { for (AnalysisFeatureList::iterator x = _transients.begin(); x != _transients.end(); ++x) {
(*x) -= _start; (*x) -= start_sample();
} }
_transient_analysis_start = _start; _transient_analysis_start = start_sample();
_transient_analysis_end = _start + _length; _transient_analysis_end = start_sample() + length_samples();
return; return;
} }
@ -1816,8 +1819,8 @@ in this and future transient-detection operations.\n\
} }
TransientDetector::cleanup_transients (_transients, pl->session().sample_rate(), 3.0); TransientDetector::cleanup_transients (_transients, pl->session().sample_rate(), 3.0);
_transient_analysis_start = _start; _transient_analysis_start = start_sample();
_transient_analysis_end = _start + _length; _transient_analysis_end = start_sample() + length_samples();
} }
/* Transient analysis uses ::read() which is relative to _start, /* Transient analysis uses ::read() which is relative to _start,
@ -1846,21 +1849,21 @@ AudioRegion::get_transients (AnalysisFeatureList& results)
return; return;
} }
Region::merge_features (results, _user_transients, _position + _transient_user_start - _start); Region::merge_features (results, _user_transients, position_sample() + _transient_user_start - start_sample());
if (!_onsets.empty ()) { if (!_onsets.empty ()) {
// onsets are invalidated when start or length changes // onsets are invalidated when start or length changes
merge_features (results, _onsets, _position); merge_features (results, _onsets, position_sample());
return; return;
} }
if ((_transient_analysis_start == _transient_analysis_end) if ((_transient_analysis_start == _transient_analysis_end)
|| _transient_analysis_start > _start || _transient_analysis_start > start_sample()
|| _transient_analysis_end < _start + _length) { || _transient_analysis_end < start_sample() + length_samples()) {
build_transients (); build_transients ();
} }
merge_features (results, _transients, _position + _transient_analysis_start - _start); merge_features (results, _transients, position_sample() + _transient_analysis_start - start_sample());
} }
/** Find areas of `silence' within a region. /** Find areas of `silence' within a region.
@ -1880,13 +1883,13 @@ AudioRegion::find_silence (Sample threshold, samplecnt_t min_length, samplecnt_t
assert (fade_length >= 0); assert (fade_length >= 0);
assert (min_length > 0); assert (min_length > 0);
samplepos_t pos = _start; samplepos_t pos = start_sample();
samplepos_t const end = _start + _length; samplepos_t const end = start_sample() + length_samples();
AudioIntervalResult silent_periods; AudioIntervalResult silent_periods;
bool in_silence = true; bool in_silence = true;
sampleoffset_t silence_start = _start; sampleoffset_t silence_start = start_sample();
while (pos < end && !itt.cancel) { while (pos < end && !itt.cancel) {
@ -1922,7 +1925,7 @@ AudioRegion::find_silence (Sample threshold, samplecnt_t min_length, samplecnt_t
} }
pos += cur_samples; pos += cur_samples;
itt.progress = (end - pos) / (double)_length; itt.progress = (end - pos) / (double) length_samples();
if (cur_samples == 0) { if (cur_samples == 0) {
assert (pos >= end); assert (pos >= end);
@ -1942,10 +1945,10 @@ AudioRegion::find_silence (Sample threshold, samplecnt_t min_length, samplecnt_t
return silent_periods; return silent_periods;
} }
Evoral::Range<samplepos_t> Temporal::Range
AudioRegion::body_range () const AudioRegion::body_range () const
{ {
return Evoral::Range<samplepos_t> (first_sample() + _fade_in->when(false) + 1, last_sample() - _fade_out->when(false)); return Temporal::Range ((nt_position() + _fade_in->back()->when).increment(), nt_end().earlier (_fade_out->back()->when));
} }
boost::shared_ptr<Region> boost::shared_ptr<Region>
@ -1963,9 +1966,9 @@ AudioRegion::get_single_other_xfade_region (bool start) const
boost::shared_ptr<RegionList> rl; boost::shared_ptr<RegionList> rl;
if (start) { if (start) {
rl = pl->regions_at (position()); rl = pl->regions_at (nt_position());
} else { } else {
rl = pl->regions_at (last_sample()); rl = pl->regions_at (nt_last());
} }
RegionList::iterator i; RegionList::iterator i;
@ -2005,7 +2008,7 @@ AudioRegion::verify_xfade_bounds (samplecnt_t len, bool start)
/* zero or > 2 regions here, don't care about len, but /* zero or > 2 regions here, don't care about len, but
it can't be longer than the region itself. it can't be longer than the region itself.
*/ */
return min (length(), len); return min (length_samples(), len);
} }
/* we overlap a single region. clamp the length of an xfade to /* we overlap a single region. clamp the length of an xfade to
@ -2014,12 +2017,11 @@ AudioRegion::verify_xfade_bounds (samplecnt_t len, bool start)
*/ */
if (start) { if (start) {
maxlen = other->latest_possible_sample() - position(); maxlen = other->latest_possible_sample() - position_sample();
} else { } else {
maxlen = last_sample() - other->earliest_possible_position(); maxlen = last_sample() - other->earliest_possible_position().samples();
} }
return min (length(), min (maxlen, len)); return min (length_samples(), min (maxlen, len));
} }

View file

@ -81,7 +81,6 @@ bool AudioSource::_build_peakfiles = false;
AudioSource::AudioSource (Session& s, const string& name) AudioSource::AudioSource (Session& s, const string& name)
: Source (s, DataType::AUDIO, name) : Source (s, DataType::AUDIO, name)
, _length (0)
, _peak_byte_max (0) , _peak_byte_max (0)
, _peaks_built (false) , _peaks_built (false)
, _peakfile_fd (-1) , _peakfile_fd (-1)
@ -98,7 +97,6 @@ AudioSource::AudioSource (Session& s, const string& name)
AudioSource::AudioSource (Session& s, const XMLNode& node) AudioSource::AudioSource (Session& s, const XMLNode& node)
: Source (s, node) : Source (s, node)
, _length (0)
, _peak_byte_max (0) , _peak_byte_max (0)
, _peaks_built (false) , _peaks_built (false)
, _peakfile_fd (-1) , _peakfile_fd (-1)
@ -151,20 +149,8 @@ AudioSource::set_state (const XMLNode& node, int /*version*/)
return 0; return 0;
} }
bool
AudioSource::empty () const
{
return _length == 0;
}
samplecnt_t
AudioSource::length (samplepos_t /*pos*/) const
{
return _length;
}
void void
AudioSource::update_length (samplecnt_t len) AudioSource::update_length (timecnt_t const & len)
{ {
if (len > _length) { if (len > _length) {
_length = len; _length = len;
@ -271,7 +257,7 @@ AudioSource::initialize_peakfile (const string& audio_path, const bool in_sessio
/* we found it in the peaks dir, so check it out */ /* we found it in the peaks dir, so check it out */
if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length(_natural_position) / _FPP) * sizeof (PeakData)))) { if (statbuf.st_size == 0 || (statbuf.st_size < (off_t) ((length().samples() / _FPP) * sizeof (PeakData)))) {
DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 is empty\n", _peakpath)); DEBUG_TRACE(DEBUG::Peaks, string_compose("Peakfile %1 is empty\n", _peakpath));
_peaks_built = false; _peaks_built = false;
} else { } else {
@ -425,7 +411,7 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos
* *
*/ */
const off_t expected_file_size = (_length / (double) samples_per_file_peak) * sizeof (PeakData); const off_t expected_file_size = (_length.samples() / (double) samples_per_file_peak) * sizeof (PeakData);
if (statbuf.st_size < expected_file_size) { if (statbuf.st_size < expected_file_size) {
warning << string_compose (_("peak file %1 is truncated from %2 to %3"), _peakpath, expected_file_size, statbuf.st_size) << endmsg; warning << string_compose (_("peak file %1 is truncated from %2 to %3"), _peakpath, expected_file_size, statbuf.st_size) << endmsg;
@ -457,9 +443,9 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos
/* fix for near-end-of-file conditions */ /* fix for near-end-of-file conditions */
if (cnt + start > _length) { if (cnt + start > _length.samples()) {
// cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl; // cerr << "too close to end @ " << _length << " given " << start << " + " << cnt << " (" << _length - start << ")" << endl;
cnt = std::max ((samplecnt_t)0, _length - start); cnt = std::max ((samplecnt_t)0, _length.samples() - start);
read_npeaks = min ((samplecnt_t) floor (cnt / samples_per_visual_peak), npeaks); read_npeaks = min ((samplecnt_t) floor (cnt / samples_per_visual_peak), npeaks);
zero_fill = npeaks - read_npeaks; zero_fill = npeaks - read_npeaks;
expected_peaks = (cnt / (double) samples_per_file_peak); expected_peaks = (cnt / (double) samples_per_file_peak);
@ -704,9 +690,9 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos
if (i == samples_read) { if (i == samples_read) {
to_read = min (chunksize, (samplecnt_t)(_length - current_sample)); to_read = min (chunksize, (samplecnt_t)(_length.samples() - current_sample));
if (current_sample >= _length) { if (current_sample >= _length.samples()) {
/* hmm, error condition - we've reached the end of the file /* hmm, error condition - we've reached the end of the file
* without generating all the peak data. cook up a zero-filled * without generating all the peak data. cook up a zero-filled
@ -719,7 +705,7 @@ AudioSource::read_peaks_with_fpp (PeakData *peaks, samplecnt_t npeaks, samplepos
} else { } else {
to_read = min (chunksize, (_length - current_sample)); to_read = min (chunksize, (_length.samples() - current_sample));
if ((samples_read = read_unlocked (raw_staging.get(), current_sample, to_read)) == 0) { if ((samples_read = read_unlocked (raw_staging.get(), current_sample, to_read)) == 0) {
@ -779,7 +765,7 @@ AudioSource::build_peaks_from_scratch ()
} }
samplecnt_t current_sample = 0; samplecnt_t current_sample = 0;
samplecnt_t cnt = _length; samplecnt_t cnt = _length.samples();
_peaks_built = false; _peaks_built = false;
boost::scoped_array<Sample> buf(new Sample[bufsize]); boost::scoped_array<Sample> buf(new Sample[bufsize]);
@ -1112,7 +1098,7 @@ samplecnt_t
AudioSource::available_peaks (double zoom_factor) const AudioSource::available_peaks (double zoom_factor) const
{ {
if (zoom_factor < _FPP) { if (zoom_factor < _FPP) {
return length(_natural_position); // peak data will come from the audio file return _length.samples(); // peak data will come from the audio file
} }
/* peak data comes from peakfile, but the filesize might not represent /* peak data comes from peakfile, but the filesize might not represent

View file

@ -308,16 +308,17 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
unload_synth (true); unload_synth (true);
midi_region.reset(); midi_region.reset();
_import_position = 0; _import_position = timepos_t (Temporal::AudioTime);
/* copy it */ /* copy it */
the_region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region, false)); the_region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (region, false));
the_region->set_position (0); the_region->set_position (timepos_t (Temporal::AudioTime));
_disk_reader->midi_playlist()->drop_regions (); _disk_reader->midi_playlist()->drop_regions ();
_disk_reader->audio_playlist()->drop_regions (); _disk_reader->audio_playlist()->drop_regions ();
_disk_reader->audio_playlist()->add_region (the_region, 0, 1); _disk_reader->audio_playlist()->add_region (the_region, timepos_t (Temporal::AudioTime), 1);
ProcessorStreams ps; ProcessorStreams ps;
{ {
@ -325,7 +326,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
if (configure_processors (&ps)) { if (configure_processors (&ps)) {
error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"), error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"),
region->n_channels()) << endmsg; region->sources().size()) << endmsg;
return; return;
} }
} }
@ -334,7 +335,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
_midi_audition = true; _midi_audition = true;
the_region.reset(); the_region.reset();
_import_position = region->position(); _import_position = region->nt_position();
/* copy it */ /* copy it */
midi_region = (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (region, false))); midi_region = (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (region, false)));
@ -362,7 +363,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
if (configure_processors (&ps)) { if (configure_processors (&ps)) {
error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"), error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"),
region->n_channels()) << endmsg; region->sources().size()) << endmsg;
unload_synth (true); unload_synth (true);
return; return;
} }
@ -380,13 +381,13 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
_seeking = false; _seeking = false;
int dir; int dir;
samplecnt_t offset; timepos_t offset;
if (_midi_audition) { if (_midi_audition) {
length = midi_region->length(); length = midi_region->nt_length();
offset = _import_position + midi_region->sync_offset (dir); offset = _import_position + midi_region->sync_offset (dir);
} else { } else {
length = the_region->length(); length = the_region->nt_length();
offset = the_region->sync_offset (dir); offset = the_region->sync_offset (dir);
} }
@ -402,7 +403,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
offset = 0; offset = 0;
} }
_disk_reader->seek (offset, true); _disk_reader->seek (offset.samples(), true);
if (_midi_audition) { if (_midi_audition) {
/* Fill MIDI buffers. /* Fill MIDI buffers.
@ -415,7 +416,7 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
_disk_reader->overwrite_existing_buffers (); _disk_reader->overwrite_existing_buffers ();
} }
current_sample = offset; current_sample = offset.samples();
g_atomic_int_set (&_auditioning, 1); g_atomic_int_set (&_auditioning, 1);
} }
@ -455,7 +456,7 @@ Auditioner::play_audition (samplecnt_t nframes)
if(!_seeking) { if(!_seeking) {
/* process audio */ /* process audio */
this_nframes = min (nframes, length - current_sample + _import_position); this_nframes = min (nframes, length.samples() - current_sample + _import_position.samples());
if (this_nframes > 0 && 0 != (ret = roll (this_nframes, current_sample, current_sample + this_nframes, need_butler))) { if (this_nframes > 0 && 0 != (ret = roll (this_nframes, current_sample, current_sample + this_nframes, need_butler))) {
silence (nframes); silence (nframes);
@ -475,7 +476,7 @@ Auditioner::play_audition (samplecnt_t nframes)
silence (nframes); silence (nframes);
} }
if (_seek_sample >= 0 && _seek_sample < length && !_seeking) { if (_seek_sample >= 0 && _seek_sample < length.samples() && !_seeking) {
_queue_panic = true; _queue_panic = true;
_seek_complete = false; _seek_complete = false;
_seeking = true; _seeking = true;
@ -483,10 +484,10 @@ Auditioner::play_audition (samplecnt_t nframes)
} }
if (!_seeking) { if (!_seeking) {
AuditionProgress(current_sample - _import_position, length); /* emit */ AuditionProgress(current_sample - _import_position.samples(), length.samples()); /* emit */
} }
if (current_sample >= length + _import_position) { if (current_sample >= (length + _import_position).samples()) {
_session.cancel_audition (); _session.cancel_audition ();
unload_synth (false); unload_synth (false);
return 0; return 0;
@ -515,7 +516,7 @@ Auditioner::seek_to_sample (sampleoffset_t pos) {
void void
Auditioner::seek_to_percent (float const pos) { Auditioner::seek_to_percent (float const pos) {
if (_seek_sample < 0 && !_seeking) { if (_seek_sample < 0 && !_seeking) {
_seek_sample = floorf(length * pos / 100.0); _seek_sample = floorf(length.samples() * pos / 100.0);
} }
} }

View file

@ -22,6 +22,8 @@
*/ */
#include <cstdio> #include <cstdio>
#include <fstream>
#include <errno.h> #include <errno.h>
#include "pbd/gstdio_compat.h" #include "pbd/gstdio_compat.h"
@ -29,6 +31,8 @@
#include "pbd/error.h" #include "pbd/error.h"
#include "temporal/timeline.h"
#include "ardour/amp.h" #include "ardour/amp.h"
#include "ardour/automatable.h" #include "ardour/automatable.h"
#include "ardour/event_type_map.h" #include "ardour/event_type_map.h"
@ -116,9 +120,9 @@ Automatable::load_automation (const string& path)
fullpath += path; fullpath += path;
} }
FILE * in = g_fopen (fullpath.c_str (), "rb"); std::ifstream in (fullpath);
if (!in) { if (in.bad()) {
warning << string_compose(_("cannot open %2 to load automation data (%3)") warning << string_compose(_("cannot open %2 to load automation data (%3)")
, fullpath, strerror (errno)) << endmsg; , fullpath, strerror (errno)) << endmsg;
return 1; return 1;
@ -128,17 +132,14 @@ Automatable::load_automation (const string& path)
set<Evoral::Parameter> tosave; set<Evoral::Parameter> tosave;
controls().clear (); controls().clear ();
while (!feof(in)) { while (!in.eof()) {
double when; Temporal::timepos_t when;
double value; double value;
uint32_t port; uint32_t port;
if (3 != fscanf (in, "%d %lf %lf", &port, &when, &value)) { in >> port; if (in.bad()) { goto bad; }
if (feof(in)) { in >> when; if (in.bad()) { goto bad; }
break; in >> value; if (in.bad()) { goto bad; }
}
goto bad;
}
Evoral::Parameter param(PluginAutomation, 0, port); Evoral::Parameter param(PluginAutomation, 0, port);
/* FIXME: this is legacy and only used for plugin inserts? I think? */ /* FIXME: this is legacy and only used for plugin inserts? I think? */
@ -146,14 +147,12 @@ Automatable::load_automation (const string& path)
c->list()->add (when, value); c->list()->add (when, value);
tosave.insert (param); tosave.insert (param);
} }
::fclose (in);
return 0; return 0;
bad: bad:
error << string_compose(_("cannot load automation data from %2"), fullpath) << endmsg; error << string_compose(_("cannot load automation data from %2"), fullpath) << endmsg;
controls().clear (); controls().clear ();
::fclose (in);
return -1; return -1;
} }
@ -404,23 +403,24 @@ Automatable::non_realtime_locate (samplepos_t now)
* compare to compare to non_realtime_transport_stop() * compare to compare to non_realtime_transport_stop()
*/ */
const bool list_did_write = !l->in_new_write_pass (); const bool list_did_write = !l->in_new_write_pass ();
c->stop_touch (-1); // time is irrelevant #warning NUTEMPO check use of domain in arbitrary irrelevant time
l->stop_touch (-1); c->stop_touch (timepos_t::zero (Temporal::AudioTime)); // time is irrelevant
l->stop_touch (timepos_t::zero (Temporal::AudioTime));
c->commit_transaction (list_did_write); c->commit_transaction (list_did_write);
l->write_pass_finished (now, Config->get_automation_thinning_factor ()); l->write_pass_finished (timepos_t (now), Config->get_automation_thinning_factor ());
if (l->automation_state () == Write) { if (l->automation_state () == Write) {
l->set_automation_state (Touch); l->set_automation_state (Touch);
} }
if (l->automation_playback ()) { if (l->automation_playback ()) {
c->set_value_unchecked (c->list ()->eval (now)); c->set_value_unchecked (c->list ()->eval (timepos_t (now)));
} }
} }
l->start_write_pass (now); l->start_write_pass (timepos_t (now));
if (rolling && am_touching) { if (rolling && am_touching) {
c->start_touch (now); c->start_touch (timepos_t (now));
} }
} }
} }
@ -450,19 +450,19 @@ Automatable::non_realtime_transport_stop (samplepos_t now, bool /*flush_processo
*/ */
const bool list_did_write = !l->in_new_write_pass (); const bool list_did_write = !l->in_new_write_pass ();
c->stop_touch (now); c->stop_touch (timepos_t (now));
l->stop_touch (now); l->stop_touch (timepos_t (now));
c->commit_transaction (list_did_write); c->commit_transaction (list_did_write);
l->write_pass_finished (now, Config->get_automation_thinning_factor ()); l->write_pass_finished (timepos_t (now), Config->get_automation_thinning_factor ());
if (l->automation_state () == Write) { if (l->automation_state () == Write) {
l->set_automation_state (Touch); l->set_automation_state (Touch);
} }
if (l->automation_playback ()) { if (l->automation_playback ()) {
c->set_value_unchecked (c->list ()->eval (now)); c->set_value_unchecked (c->list ()->eval (timepos_t (now)));
} }
} }
} }
@ -547,7 +547,7 @@ Automatable::control_factory(const Evoral::Parameter& param)
if (!Variant::type_is_numeric(desc.datatype)) { if (!Variant::type_is_numeric(desc.datatype)) {
make_list = false; // Can't automate non-numeric data yet make_list = false; // Can't automate non-numeric data yet
} else { } else {
list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc)); list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc, Temporal::AudioTime));
} }
control = new PluginInsert::PluginPropertyControl(pi, param, desc, list); control = new PluginInsert::PluginPropertyControl(pi, param, desc, list);
} }
@ -593,7 +593,8 @@ Automatable::control_factory(const Evoral::Parameter& param)
} }
if (make_list && !list) { if (make_list && !list) {
list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc)); #warning NUTEMPO what time domain to use here?
list = boost::shared_ptr<AutomationList>(new AutomationList(param, desc, Temporal::AudioTime));
} }
if (!control) { if (!control) {
@ -638,7 +639,7 @@ Automatable::clear_controls ()
} }
bool bool
Automatable::find_next_event (double start, double end, Evoral::ControlEvent& next_event, bool only_active) const Automatable::find_next_event (timepos_t const & start, timepos_t const & end, Evoral::ControlEvent& next_event, bool only_active) const
{ {
next_event.when = start <= end ? std::numeric_limits<double>::max() : 0; next_event.when = start <= end ? std::numeric_limits<double>::max() : 0;
@ -670,7 +671,7 @@ Automatable::find_next_event (double start, double end, Evoral::ControlEvent& ne
} }
void void
Automatable::find_next_ac_event (boost::shared_ptr<AutomationControl> c, double start, double end, Evoral::ControlEvent& next_event) const Automatable::find_next_ac_event (boost::shared_ptr<AutomationControl> c, timepos_t const & start, timepos_t const & end, Evoral::ControlEvent& next_event) const
{ {
assert (start <= end); assert (start <= end);
@ -697,7 +698,7 @@ Automatable::find_next_ac_event (boost::shared_ptr<AutomationControl> c, double
} }
void void
Automatable::find_prev_ac_event (boost::shared_ptr<AutomationControl> c, double start, double end, Evoral::ControlEvent& next_event) const Automatable::find_prev_ac_event (boost::shared_ptr<AutomationControl> c, timepos_t const & start, timepos_t const & end, Evoral::ControlEvent& next_event) const
{ {
assert (start > end); assert (start > end);
boost::shared_ptr<SlavableAutomationControl> sc boost::shared_ptr<SlavableAutomationControl> sc

View file

@ -100,7 +100,7 @@ double
AutomationControl::get_value() const AutomationControl::get_value() const
{ {
bool from_list = alist() && alist()->automation_playback(); bool from_list = alist() && alist()->automation_playback();
return Control::get_double (from_list, _session.transport_sample()); return Control::get_double (from_list, timepos_t (_session.transport_sample()));
} }
double double
@ -128,7 +128,7 @@ AutomationControl::set_value (double val, PBD::Controllable::GroupControlDisposi
} }
if (_list && !touching () && alist()->automation_state() == Latch && _session.transport_rolling ()) { if (_list && !touching () && alist()->automation_state() == Latch && _session.transport_rolling ()) {
start_touch (_session.transport_sample ()); start_touch (timepos_t (_session.transport_sample ()));
} }
/* enforce strict double/boolean value mapping */ /* enforce strict double/boolean value mapping */
@ -170,7 +170,7 @@ AutomationControl::automation_run (samplepos_t start, pframes_t nframes)
assert (_list); assert (_list);
bool valid = false; bool valid = false;
double val = _list->rt_safe_eval (start, valid); double val = _list->rt_safe_eval (timepos_t (start), valid);
if (!valid) { if (!valid) {
return; return;
} }
@ -216,7 +216,7 @@ AutomationControl::actually_set_value (double value, PBD::Controllable::GroupCon
to_list = false; to_list = false;
} }
Control::set_double (value, pos, to_list); Control::set_double (value, timepos_t (pos), to_list);
if (old_value != (float)value) { if (old_value != (float)value) {
#if 0 #if 0
@ -254,9 +254,10 @@ AutomationControl::set_automation_state (AutoState as)
if (as == Write) { if (as == Write) {
AutomationWatch::instance().add_automation_watch (boost::dynamic_pointer_cast<AutomationControl>(shared_from_this())); AutomationWatch::instance().add_automation_watch (boost::dynamic_pointer_cast<AutomationControl>(shared_from_this()));
} else if (as & (Touch | Latch)) { } else if (as & (Touch | Latch)) {
#warning NUTEMPO fixme timestamps here are always in samples ... should match list time domain
if (alist()->empty()) { if (alist()->empty()) {
Control::set_double (val, _session.current_start_sample (), true); Control::set_double (val, timepos_t (_session.current_start_sample ()), true);
Control::set_double (val, _session.current_end_sample (), true); Control::set_double (val, timepos_t (_session.current_end_sample ()), true);
Changed (true, Controllable::NoGroup); Changed (true, Controllable::NoGroup);
} }
if (!touching()) { if (!touching()) {
@ -277,7 +278,7 @@ AutomationControl::set_automation_state (AutoState as)
} }
void void
AutomationControl::start_touch (double when) AutomationControl::start_touch (timepos_t const & when)
{ {
if (!_list || touching ()) { if (!_list || touching ()) {
return; return;
@ -300,7 +301,7 @@ AutomationControl::start_touch (double when)
} }
void void
AutomationControl::stop_touch (double when) AutomationControl::stop_touch (timepos_t const & when)
{ {
if (!_list || !touching ()) { if (!_list || !touching ()) {
return; return;

View file

@ -28,6 +28,8 @@
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
#include "temporal/types_convert.h"
#include "ardour/automation_list.h" #include "ardour/automation_list.h"
#include "ardour/beats_samples_converter.h" #include "ardour/beats_samples_converter.h"
#include "ardour/event_type_map.h" #include "ardour/event_type_map.h"
@ -60,8 +62,8 @@ static void dumpit (const AutomationList& al, string prefix = "")
cerr << "\n"; cerr << "\n";
} }
#endif #endif
AutomationList::AutomationList (const Evoral::Parameter& id, const Evoral::ParameterDescriptor& desc) AutomationList::AutomationList (const Evoral::Parameter& id, const Evoral::ParameterDescriptor& desc, Temporal::TimeDomain time_domain)
: ControlList(id, desc) : ControlList(id, desc, time_domain)
, _before (0) , _before (0)
{ {
_state = Off; _state = Off;
@ -74,8 +76,8 @@ AutomationList::AutomationList (const Evoral::Parameter& id, const Evoral::Param
AutomationListCreated(this); AutomationListCreated(this);
} }
AutomationList::AutomationList (const Evoral::Parameter& id) AutomationList::AutomationList (const Evoral::Parameter& id, Temporal::TimeDomain time_domain)
: ControlList(id, ARDOUR::ParameterDescriptor(id)) : ControlList(id, ARDOUR::ParameterDescriptor(id), time_domain)
, _before (0) , _before (0)
{ {
_state = Off; _state = Off;
@ -102,7 +104,7 @@ AutomationList::AutomationList (const AutomationList& other)
AutomationListCreated(this); AutomationListCreated(this);
} }
AutomationList::AutomationList (const AutomationList& other, double start, double end) AutomationList::AutomationList (const AutomationList& other, timepos_t const & start, timepos_t const & end)
: ControlList(other, start, end) : ControlList(other, start, end)
, _before (0) , _before (0)
{ {
@ -119,7 +121,7 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
* in or below the AutomationList node. It is used if @param id is non-null. * in or below the AutomationList node. It is used if @param id is non-null.
*/ */
AutomationList::AutomationList (const XMLNode& node, Evoral::Parameter id) AutomationList::AutomationList (const XMLNode& node, Evoral::Parameter id)
: ControlList(id, ARDOUR::ParameterDescriptor(id)) : ControlList(id, ARDOUR::ParameterDescriptor(id), Temporal::AudioTime) /* domain may change in ::set_state */
, _before (0) , _before (0)
{ {
g_atomic_int_set (&_touching, 0); g_atomic_int_set (&_touching, 0);
@ -145,9 +147,10 @@ AutomationList::~AutomationList()
boost::shared_ptr<Evoral::ControlList> boost::shared_ptr<Evoral::ControlList>
AutomationList::create(const Evoral::Parameter& id, AutomationList::create(const Evoral::Parameter& id,
const Evoral::ParameterDescriptor& desc) const Evoral::ParameterDescriptor& desc,
Temporal::TimeDomain time_domain)
{ {
return boost::shared_ptr<Evoral::ControlList>(new AutomationList(id, desc)); return boost::shared_ptr<Evoral::ControlList>(new AutomationList(id, desc, time_domain));
} }
void void
@ -245,20 +248,20 @@ AutomationList::default_interpolation () const
} }
void void
AutomationList::start_write_pass (double when) AutomationList::start_write_pass (timepos_t const & when)
{ {
snapshot_history (true); snapshot_history (true);
ControlList::start_write_pass (when); ControlList::start_write_pass (when);
} }
void void
AutomationList::write_pass_finished (double when, double thinning_factor) AutomationList::write_pass_finished (timepos_t const & when, double thinning_factor)
{ {
ControlList::write_pass_finished (when, thinning_factor); ControlList::write_pass_finished (when, thinning_factor);
} }
void void
AutomationList::start_touch (double when) AutomationList::start_touch (timepos_t const & when)
{ {
if (_state == Touch) { if (_state == Touch) {
start_write_pass (when); start_write_pass (when);
@ -268,7 +271,7 @@ AutomationList::start_touch (double when)
} }
void void
AutomationList::stop_touch (double) AutomationList::stop_touch (timepos_t const & /* not used */)
{ {
if (g_atomic_int_get (&_touching) == 0) { if (g_atomic_int_get (&_touching) == 0) {
/* this touch has already been stopped (probably by Automatable::transport_stopped), /* this touch has already been stopped (probably by Automatable::transport_stopped),
@ -315,26 +318,27 @@ AutomationList::thaw ()
} }
bool bool
AutomationList::paste (const ControlList& alist, double pos, BeatsSamplesConverter const& bfc) AutomationList::paste (const ControlList& alist, timepos_t const & pos, BeatsSamplesConverter const& bfc)
{ {
AutomationType src_type = (AutomationType)alist.parameter().type(); if (time_domain() == alist.time_domain()) {
AutomationType dst_type = (AutomationType)_parameter.type();
if (parameter_is_midi (src_type) == parameter_is_midi (dst_type)) {
return ControlList::paste (alist, pos); return ControlList::paste (alist, pos);
} }
bool to_sample = parameter_is_midi (src_type);
/* time domains differ - need to map the time of all points in alist
* into our time domain
*/
const bool to_sample = (time_domain() == Temporal::AudioTime);
ControlList cl (alist); ControlList cl (alist);
cl.clear (); cl.clear ();
for (const_iterator i = alist.begin ();i != alist.end (); ++i) { for (const_iterator i = alist.begin ();i != alist.end (); ++i) {
double when = (*i)->when;
if (to_sample) { if (to_sample) {
when = bfc.to (Temporal::Beats::from_double ((*i)->when)); cl.fast_simple_add (timepos_t ((*i)->when.samples()), (*i)->value);
} else { } else {
when = bfc.from ((*i)->when).to_double (); cl.fast_simple_add (timepos_t ((*i)->when.beats ()), (*i)->value);
} }
cl.fast_simple_add (when, (*i)->value);
} }
return ControlList::paste (cl, pos); return ControlList::paste (cl, pos);
} }
@ -359,6 +363,7 @@ AutomationList::state (bool save_auto_state, bool need_lock)
root->set_property ("automation-id", EventTypeMap::instance().to_symbol(_parameter)); root->set_property ("automation-id", EventTypeMap::instance().to_symbol(_parameter));
root->set_property ("id", id()); root->set_property ("id", id());
root->set_property ("interpolation-style", _interpolation); root->set_property ("interpolation-style", _interpolation);
root->set_property ("time-domain", enum_2_string (time_domain()));
if (save_auto_state) { if (save_auto_state) {
/* never serialize state with Write enabled - too dangerous /* never serialize state with Write enabled - too dangerous
@ -432,13 +437,13 @@ AutomationList::deserialize_events (const XMLNode& node)
std::string x_str; std::string x_str;
std::string y_str; std::string y_str;
double x; timepos_t x;
double y; double y;
bool ok = true; bool ok = true;
while (str) { while (str) {
str >> x_str; str >> x_str;
if (!str || !PBD::string_to<double> (x_str, x)) { if (!str || !PBD::string_to<timepos_t> (x_str, x)) {
break; break;
} }
str >> y_str; str >> y_str;
@ -469,6 +474,11 @@ AutomationList::set_state (const XMLNode& node, int version)
XMLNodeList nlist = node.children(); XMLNodeList nlist = node.children();
XMLNode* nsos; XMLNode* nsos;
XMLNodeIterator niter; XMLNodeIterator niter;
Temporal::TimeDomain time_domain;
if (node.get_property ("time-domain", time_domain)) {
set_time_domain (time_domain);
}
if (node.name() == X_("events")) { if (node.name() == X_("events")) {
/* partial state setting*/ /* partial state setting*/
@ -505,7 +515,7 @@ AutomationList::set_state (const XMLNode& node, int version)
} }
y = std::min ((double)_desc.upper, std::max ((double)_desc.lower, y)); y = std::min ((double)_desc.upper, std::max ((double)_desc.lower, y));
fast_simple_add (x, y); fast_simple_add (timepos_t (x), y);
} }
thaw (); thaw ();

View file

@ -87,7 +87,8 @@ AutomationWatch::add_automation_watch (boost::shared_ptr<AutomationControl> ac)
DEBUG_TRACE (DEBUG::Automation, string_compose ("\ttransport is rolling @ %1, audible = %2so enter write pass\n", DEBUG_TRACE (DEBUG::Automation, string_compose ("\ttransport is rolling @ %1, audible = %2so enter write pass\n",
_session->transport_speed(), _session->audible_sample())); _session->transport_speed(), _session->audible_sample()));
/* add a guard point since we are already moving */ /* add a guard point since we are already moving */
ac->list()->set_in_write_pass (true, true, _session->audible_sample()); #warning NUTEMPO QUESTION should the time be in the domain of the list ?
ac->list()->set_in_write_pass (true, true, timepos_t (_session->audible_sample()));
} }
/* we can't store shared_ptr<Destructible> in connections because it /* we can't store shared_ptr<Destructible> in connections because it
@ -142,7 +143,7 @@ AutomationWatch::transport_stop_automation_watches (samplepos_t when)
} }
for (AutomationWatches::iterator i = tmp.begin(); i != tmp.end(); ++i) { for (AutomationWatches::iterator i = tmp.begin(); i != tmp.end(); ++i) {
(*i)->stop_touch (when); (*i)->stop_touch (timepos_t (when));
} }
} }
@ -165,7 +166,7 @@ AutomationWatch::timer ()
if (sc) { if (sc) {
val = sc->reduce_by_masters (val, true); val = sc->reduce_by_masters (val, true);
} }
(*aw)->list()->add (time, val, true); (*aw)->list()->add (timepos_t (time), val, true);
} }
} }
} else if (time != _last_time) { //transport stopped or reversed. stop the automation pass and start a new one (for bonus points, someday store the previous pass in an undo record) } else if (time != _last_time) { //transport stopped or reversed. stop the automation pass and start a new one (for bonus points, someday store the previous pass in an undo record)
@ -175,7 +176,7 @@ AutomationWatch::timer ()
(*aw)->alist()->automation_write())); (*aw)->alist()->automation_write()));
(*aw)->list()->set_in_write_pass (false); (*aw)->list()->set_in_write_pass (false);
if ( (*aw)->alist()->automation_write() ) { if ( (*aw)->alist()->automation_write() ) {
(*aw)->list()->set_in_write_pass (true, true, time); (*aw)->list()->set_in_write_pass (true, true, timepos_t (time));
} }
} }
} }

View file

@ -18,16 +18,17 @@
#include "pbd/stacktrace.h" #include "pbd/stacktrace.h"
#include "temporal/tempo.h"
#include "ardour/beats_samples_converter.h" #include "ardour/beats_samples_converter.h"
#include "ardour/tempo.h"
namespace ARDOUR { namespace ARDOUR {
/** Takes a positive duration in quarter-note beats and considers it as a distance from the origin /** Takes a positive duration in quarter-note beats and considers it as a distance from the origin
* supplied to the constructor. Returns the equivalent number of samples, * supplied to the constructor. Returns the equivalent number of samples,
* taking tempo changes into account. * taking tempo changes into account.
*/ */
samplepos_t samplecnt_t
BeatsSamplesConverter::to (Temporal::Beats beats) const BeatsSamplesConverter::to (Temporal::Beats beats) const
{ {
if (beats < Temporal::Beats()) { if (beats < Temporal::Beats()) {
@ -35,37 +36,17 @@ BeatsSamplesConverter::to (Temporal::Beats beats) const
PBD::stacktrace (std::cerr, 30); PBD::stacktrace (std::cerr, 30);
return 0; return 0;
} }
return _tempo_map.samplepos_plus_qn (_origin_b, beats) - _origin_b; return _tempo_map.sample_quarters_delta_as_samples (_origin, beats) - _origin;
} }
/** Takes a duration in samples and considers it as a distance from the origin /** Takes a positive duration in superclocks and considers it as a distance from the origin
* supplied to the constructor. Returns the equivalent number of quarter-note beats, * supplied to the constructor. Returns the equivalent number of quarter-note beats,
* taking tempo changes into account. * taking tempo changes into account.
*
* Distance must be positive because we assume we are walking forward from our origin.
*/ */
Temporal::Beats Temporal::Beats
BeatsSamplesConverter::from (samplepos_t samples) const BeatsSamplesConverter::from (samplecnt_t distance) const
{ {
return _tempo_map.framewalk_to_qn (_origin_b, samples); return _tempo_map.sample_delta_as_quarters (_origin, distance);
} }
/** As above, but with quarter-note beats in double instead (for GUI). */
samplepos_t
DoubleBeatsSamplesConverter::to (double beats) const
{
if (beats < 0.0) {
std::cerr << "negative beats passed to BFC: " << beats << std::endl;
PBD::stacktrace (std::cerr, 30);
return 0;
}
return _tempo_map.samplepos_plus_qn (_origin_b, Temporal::Beats(beats)) - _origin_b;
}
/** As above, but with quarter-note beats in double instead (for GUI). */
double
DoubleBeatsSamplesConverter::from (samplepos_t samples) const
{
return _tempo_map.framewalk_to_qn (_origin_b, samples).to_double();
}
} /* namespace ARDOUR */

View file

@ -56,7 +56,7 @@ bool
Convolution::add_impdata ( Convolution::add_impdata (
uint32_t c_in, uint32_t c_in,
uint32_t c_out, uint32_t c_out,
boost::shared_ptr<Readable> readable, boost::shared_ptr<AudioReadable> readable,
float gain, float gain,
uint32_t pre_delay, uint32_t pre_delay,
sampleoffset_t offset, sampleoffset_t offset,
@ -66,7 +66,7 @@ Convolution::add_impdata (
if (_configured || c_in >= _n_inputs || c_out >= _n_outputs) { if (_configured || c_in >= _n_inputs || c_out >= _n_outputs) {
return false; return false;
} }
if (!readable || readable->readable_length () <= offset || readable->n_channels () <= channel) { if (!readable || readable->readable_length_samples () <= offset || readable->n_channels () <= channel) {
return false; return false;
} }
@ -104,7 +104,7 @@ Convolution::restart ()
_max_size = 0; _max_size = 0;
for (std::vector<ImpData>::const_iterator i = _impdata.begin (); i != _impdata.end (); ++i) { for (std::vector<ImpData>::const_iterator i = _impdata.begin (); i != _impdata.end (); ++i) {
_max_size = std::max (_max_size, (uint32_t)i->readable_length ()); _max_size = std::max (_max_size, (uint32_t)i->readable_length_samples ());
} }
int rv = _convproc.configure ( int rv = _convproc.configure (
@ -121,7 +121,7 @@ Convolution::restart ()
const float ir_gain = i->gain; const float ir_gain = i->gain;
const uint32_t ir_delay = i->delay; const uint32_t ir_delay = i->delay;
const uint32_t ir_len = i->readable_length (); const uint32_t ir_len = i->readable_length_samples ();
while (true) { while (true) {
float ir[8192]; float ir[8192];
@ -235,14 +235,14 @@ Convolver::Convolver (
{ {
_threaded = true; _threaded = true;
std::vector<boost::shared_ptr<Readable> > readables = Readable::load (_session, path); std::vector<boost::shared_ptr<AudioReadable> > readables = AudioReadable::load (_session, path);
if (readables.empty ()) { if (readables.empty ()) {
PBD::error << string_compose (_("Convolver: IR \"%1\" no usable audio-channels sound."), path) << endmsg; PBD::error << string_compose (_("Convolver: IR \"%1\" no usable audio-channels sound."), path) << endmsg;
throw failed_constructor (); throw failed_constructor ();
} }
if (readables[0]->readable_length () > 0x1000000 /*2^24*/) { if (readables[0]->readable_length_samples () > 0x1000000 /*2^24*/) {
PBD::error << string_compose (_("Convolver: IR \"%1\" file too long."), path) << endmsg; PBD::error << string_compose (_("Convolver: IR \"%1\" file too long."), path) << endmsg;
throw failed_constructor (); throw failed_constructor ();
} }
@ -297,7 +297,7 @@ Convolver::Convolver (
io_i = (c / n_outputs ()) % n_inputs (); io_i = (c / n_outputs ()) % n_inputs ();
} }
boost::shared_ptr<Readable> r = readables[ir_c]; boost::shared_ptr<AudioReadable> r = readables[ir_c];
assert (r->n_channels () == 1); assert (r->n_channels () == 1);
const float chan_gain = _ir_settings.gain * _ir_settings.channel_gain[c]; const float chan_gain = _ir_settings.gain * _ir_settings.channel_gain[c];

View file

@ -349,14 +349,14 @@ DiskIOProcessor::ChannelInfo::~ChannelInfo ()
*/ */
void void
DiskIOProcessor::get_location_times(const Location* location, DiskIOProcessor::get_location_times(const Location* location,
samplepos_t* start, timepos_t* start,
samplepos_t* end, timepos_t* end,
samplepos_t* length) timecnt_t* length)
{ {
if (location) { if (location) {
*start = location->start(); *start = location->start();
*end = location->end(); *end = location->end();
*length = *end - *start; *length = location->length();
} }
} }

View file

@ -23,7 +23,7 @@
#include "pbd/memento_command.h" #include "pbd/memento_command.h"
#include "pbd/playback_buffer.h" #include "pbd/playback_buffer.h"
#include "evoral/Range.h" #include "temporal/range.h"
#include "ardour/amp.h" #include "ardour/amp.h"
#include "ardour/audio_buffer.h" #include "ardour/audio_buffer.h"
@ -401,8 +401,9 @@ DiskReader::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
samplepos_t ss = start_sample; samplepos_t ss = start_sample;
Location* loc = _loop_location; Location* loc = _loop_location;
if (loc) { if (loc) {
Evoral::Range<samplepos_t> loop_range (loc->start (), loc->end () - 1); Temporal::Range loop_range (loc->start (), loc->end ());
ss = loop_range.squish (playback_sample); ss = loop_range.squish (timepos_t (playback_sample)).samples();
playback_sample = ss;
} }
if (ss != playback_sample) { if (ss != playback_sample) {
if (can_internal_playback_seek (ss - playback_sample)) { if (can_internal_playback_seek (ss - playback_sample)) {
@ -492,8 +493,8 @@ midi:
Location* loc = _loop_location; Location* loc = _loop_location;
if (loc) { if (loc) {
Evoral::Range<samplepos_t> loop_range (loc->start (), loc->end () - 1); Temporal::Range loop_range (loc->start (), loc->end ());
playback_sample = loop_range.squish (playback_sample); playback_sample = loop_range.squish (timepos_t (playback_sample)).samples();
} }
if (_playlists[DataType::AUDIO]) { if (_playlists[DataType::AUDIO]) {
@ -990,7 +991,7 @@ DiskReader::audio_read (Sample* sum_buffer,
{ {
samplecnt_t this_read = 0; samplecnt_t this_read = 0;
bool reloop = false; bool reloop = false;
samplepos_t loop_end = 0; samplepos_t loop_end = 0;
samplepos_t loop_start = 0; samplepos_t loop_start = 0;
Location* loc = 0; Location* loc = 0;
const samplecnt_t rcnt = cnt; const samplecnt_t rcnt = cnt;
@ -1008,12 +1009,11 @@ DiskReader::audio_read (Sample* sum_buffer,
*/ */
if ((loc = _loop_location) != 0) { if ((loc = _loop_location) != 0) {
loop_start = loc->start (); loop_start = loc->start_sample ();
loop_end = loc->end (); loop_end = loc->end_sample ();
/* Evoral::Range has inclusive range semantics. Ugh. Hence the -1 */ const Temporal::Range loop_range (loc->start(), loc->end());
const Evoral::Range<samplepos_t> loop_range (loop_start, loop_end - 1); start = loop_range.squish (timepos_t (start)).samples();
start = loop_range.squish (start);
} }
} else { } else {
@ -1047,7 +1047,7 @@ DiskReader::audio_read (Sample* sum_buffer,
* useful after the return from AudioPlayback::read() * useful after the return from AudioPlayback::read()
*/ */
if (audio_playlist ()->read (sum_buffer, mixdown_buffer, gain_buffer, start, this_read, channel) != this_read) { if (audio_playlist ()->read (sum_buffer, mixdown_buffer, gain_buffer, timepos_t (start), timecnt_t::from_samples (this_read), channel) != this_read) {
error << string_compose (_("DiskReader %1: cannot read %2 from playlist at sample %3"), id (), this_read, start) << endmsg; error << string_compose (_("DiskReader %1: cannot read %2 from playlist at sample %3"), id (), this_read, start) << endmsg;
return 0; return 0;
} }
@ -1066,9 +1066,9 @@ DiskReader::audio_read (Sample* sum_buffer,
loop_declick_out.run (sum_buffer, start, start + this_read); loop_declick_out.run (sum_buffer, start, start + this_read);
break; break;
case XFadeLoop: case XFadeLoop:
if (last_refill_loop_start != loc->start() || rci->pre_loop_buffer == 0) { if (last_refill_loop_start != loop_start || rci->pre_loop_buffer == 0) {
setup_preloop_buffer (); setup_preloop_buffer ();
last_refill_loop_start = loc->start(); last_refill_loop_start = loop_start;
} }
maybe_xfade_loop (sum_buffer, start, start + this_read, rci); maybe_xfade_loop (sum_buffer, start, start + this_read, rci);
break; break;
@ -1345,7 +1345,7 @@ out:
} }
void void
DiskReader::playlist_ranges_moved (list<Evoral::RangeMove<samplepos_t> > const& movements_samples, bool from_undo_or_shift) DiskReader::playlist_ranges_moved (list<Temporal::RangeMove> const& movements, bool from_undo_or_shift)
{ {
/* If we're coming from an undo, it will have handled /* If we're coming from an undo, it will have handled
* automation undo (it must, since automation-follows-regions * automation undo (it must, since automation-follows-regions
@ -1364,14 +1364,6 @@ DiskReader::playlist_ranges_moved (list<Evoral::RangeMove<samplepos_t> > const&
return; return;
} }
list<Evoral::RangeMove<double> > movements;
for (list<Evoral::RangeMove<samplepos_t> >::const_iterator i = movements_samples.begin ();
i != movements_samples.end ();
++i) {
movements.push_back (Evoral::RangeMove<double> (i->from, i->length, i->to));
}
/* move panner automation */ /* move panner automation */
boost::shared_ptr<Pannable> pannable = _track.pannable (); boost::shared_ptr<Pannable> pannable = _track.pannable ();
Evoral::ControlSet::Controls& c (pannable->controls ()); Evoral::ControlSet::Controls& c (pannable->controls ());
@ -1393,22 +1385,17 @@ DiskReader::playlist_ranges_moved (list<Evoral::RangeMove<samplepos_t> > const&
} }
} }
/* move processor automation */ /* move processor automation */
_track.foreach_processor (boost::bind (&DiskReader::move_processor_automation, this, _1, movements_samples)); _track.foreach_processor (boost::bind (&DiskReader::move_processor_automation, this, _1, movements));
} }
void void
DiskReader::move_processor_automation (boost::weak_ptr<Processor> p, list<Evoral::RangeMove<samplepos_t> > const& movements_samples) DiskReader::move_processor_automation (boost::weak_ptr<Processor> p, list<Temporal::RangeMove> const& movements)
{ {
boost::shared_ptr<Processor> processor (p.lock ()); boost::shared_ptr<Processor> processor (p.lock ());
if (!processor) { if (!processor) {
return; return;
} }
list<Evoral::RangeMove<double> > movements;
for (list<Evoral::RangeMove<samplepos_t> >::const_iterator i = movements_samples.begin (); i != movements_samples.end (); ++i) {
movements.push_back (Evoral::RangeMove<double> (i->from, i->length, i->to));
}
set<Evoral::Parameter> const a = processor->what_can_be_automated (); set<Evoral::Parameter> const a = processor->what_can_be_automated ();
for (set<Evoral::Parameter>::const_iterator i = a.begin (); i != a.end (); ++i) { for (set<Evoral::Parameter>::const_iterator i = a.begin (); i != a.end (); ++i) {
@ -1480,18 +1467,19 @@ DiskReader::get_midi_playback (MidiBuffer& dst, samplepos_t start_sample, sample
if (loc) { if (loc) {
/* Evoral::Range has inclusive range semantics. Ugh. Hence the -1 */ /* Evoral::Range has inclusive range semantics. Ugh. Hence the -1 */
const Evoral::Range<samplepos_t> loop_range (loc->start (), loc->end () - 1); const Temporal::Range loop_range (loc->start (), loc->end ());
samplepos_t effective_start = start_sample; samplepos_t effective_start = start_sample;
samplecnt_t cnt = nframes; samplecnt_t cnt = nframes;
sampleoffset_t offset = 0; sampleoffset_t offset = 0;
const samplepos_t loop_end = loc->end_sample();
DEBUG_TRACE (DEBUG::MidiDiskIO, string_compose ("LOOP read, loop is %1..%2 range is %3..%4 nf %5\n", loc->start (), loc->end (), start_sample, end_sample, nframes)); DEBUG_TRACE (DEBUG::MidiDiskIO, string_compose ("LOOP read, loop is %1..%2 range is %3..%4 nf %5\n", loc->start (), loc->end (), start_sample, end_sample, nframes));
do { do {
samplepos_t effective_end; samplepos_t effective_end;
effective_start = loop_range.squish (effective_start); effective_start = loop_range.squish (timepos_t (effective_start)).samples();
effective_end = min (effective_start + cnt, loc->end ()); effective_end = min (effective_start + cnt, loop_end);
assert (effective_end > effective_start); assert (effective_end > effective_start);
const samplecnt_t this_read = effective_end - effective_start; const samplecnt_t this_read = effective_end - effective_start;
@ -1739,8 +1727,8 @@ DiskReader::Declicker::run (Sample* buf, samplepos_t read_start, samplepos_t rea
* see also DiskReader::maybe_xfade_loop() * see also DiskReader::maybe_xfade_loop()
*/ */
switch (Evoral::coverage (fade_start, fade_end, read_start, read_end)) { switch (Temporal::coverage_exclusive_ends (fade_start, fade_end, read_start, read_end)) {
case Evoral::OverlapInternal: case Temporal::OverlapInternal:
/* note: start and end points cannot coincide (see evoral/Range.h) /* note: start and end points cannot coincide (see evoral/Range.h)
* *
* read range is entirely within fade range * read range is entirely within fade range
@ -1750,7 +1738,7 @@ DiskReader::Declicker::run (Sample* buf, samplepos_t read_start, samplepos_t rea
n = read_end - read_start; n = read_end - read_start;
break; break;
case Evoral::OverlapExternal: case Temporal::OverlapExternal:
/* read range extends on either side of fade range /* read range extends on either side of fade range
* *
* External allows coincidental start & end points, so check for that * External allows coincidental start & end points, so check for that
@ -1767,14 +1755,14 @@ DiskReader::Declicker::run (Sample* buf, samplepos_t read_start, samplepos_t rea
} }
break; break;
case Evoral::OverlapStart: case Temporal::OverlapStart:
/* read range starts before and ends within fade or at same end as fade */ /* read range starts before and ends within fade or at same end as fade */
n = fade_end - read_start; n = fade_end - read_start;
vo = 0; vo = 0;
bo = fade_start - read_start; bo = fade_start - read_start;
break; break;
case Evoral::OverlapEnd: case Temporal::OverlapEnd:
/* read range starts within fade range, but possibly at it's end, so check */ /* read range starts within fade range, but possibly at it's end, so check */
if (read_start == fade_end) { if (read_start == fade_end) {
/* nothing to do */ /* nothing to do */
@ -1785,7 +1773,7 @@ DiskReader::Declicker::run (Sample* buf, samplepos_t read_start, samplepos_t rea
n = fade_end - read_start; n = fade_end - read_start;
break; break;
case Evoral::OverlapNone: case Temporal::OverlapNone:
/* no overlap ... nothing to do */ /* no overlap ... nothing to do */
return; return;
} }
@ -1818,8 +1806,8 @@ DiskReader::maybe_xfade_loop (Sample* buf, samplepos_t read_start, samplepos_t r
* see also DiskReader::Declicker::run() * see also DiskReader::Declicker::run()
*/ */
switch (Evoral::coverage (fade_start, fade_end, read_start, read_end)) { switch (Temporal::coverage_exclusive_ends (fade_start, fade_end, read_start, read_end)) {
case Evoral::OverlapInternal: case Temporal::OverlapInternal:
/* note: start and end points cannot coincide (see evoral/Range.h) /* note: start and end points cannot coincide (see evoral/Range.h)
* *
* read range is entirely within fade range * read range is entirely within fade range
@ -1829,7 +1817,7 @@ DiskReader::maybe_xfade_loop (Sample* buf, samplepos_t read_start, samplepos_t r
n = read_end - read_start; n = read_end - read_start;
break; break;
case Evoral::OverlapExternal: case Temporal::OverlapExternal:
/* read range extends on either side of fade range /* read range extends on either side of fade range
* *
* External allows coincidental start & end points, so check for that * External allows coincidental start & end points, so check for that
@ -1846,14 +1834,14 @@ DiskReader::maybe_xfade_loop (Sample* buf, samplepos_t read_start, samplepos_t r
} }
break; break;
case Evoral::OverlapStart: case Temporal::OverlapStart:
/* read range starts before and ends within fade or at same end as fade */ /* read range starts before and ends within fade or at same end as fade */
n = read_end - fade_start; n = read_end - fade_start;
vo = 0; vo = 0;
bo = fade_start - read_start; bo = fade_start - read_start;
break; break;
case Evoral::OverlapEnd: case Temporal::OverlapEnd:
/* read range starts within fade range, but possibly at it's end, so check */ /* read range starts within fade range, but possibly at it's end, so check */
if (read_start == fade_end) { if (read_start == fade_end) {
/* nothing to do */ /* nothing to do */
@ -1864,7 +1852,7 @@ DiskReader::maybe_xfade_loop (Sample* buf, samplepos_t read_start, samplepos_t r
n = fade_end - read_start; n = fade_end - read_start;
break; break;
case Evoral::OverlapNone: case Temporal::OverlapNone:
/* no overlap ... nothing to do */ /* no overlap ... nothing to do */
return; return;
} }
@ -1912,8 +1900,8 @@ void
DiskReader::reset_loop_declick (Location* loc, samplecnt_t sr) DiskReader::reset_loop_declick (Location* loc, samplecnt_t sr)
{ {
if (loc) { if (loc) {
loop_declick_in.reset (loc->start (), loc->end (), true, sr); loop_declick_in.reset (loc->start_sample (), loc->end_sample (), true, sr);
loop_declick_out.reset (loc->start (), loc->end (), false, sr); loop_declick_out.reset (loc->start_sample (), loc->end_sample (), false, sr);
} else { } else {
loop_declick_in.reset (0, 0, true, sr); loop_declick_in.reset (0, 0, true, sr);
loop_declick_out.reset (0, 0, false, sr); loop_declick_out.reset (0, 0, false, sr);
@ -1946,6 +1934,8 @@ DiskReader::setup_preloop_buffer ()
Location* loc = _loop_location; Location* loc = _loop_location;
boost::scoped_array<Sample> mix_buf (new Sample[loop_fade_length]); boost::scoped_array<Sample> mix_buf (new Sample[loop_fade_length]);
boost::scoped_array<Sample> gain_buf (new Sample[loop_fade_length]); boost::scoped_array<Sample> gain_buf (new Sample[loop_fade_length]);
const timepos_t read_start = timepos_t (loc->start_sample() - loop_declick_out.fade_length);
const timecnt_t read_cnt = timecnt_t (loop_declick_out.fade_length);
uint32_t channel = 0; uint32_t channel = 0;
@ -1955,7 +1945,7 @@ DiskReader::setup_preloop_buffer ()
rci->resize_preloop (loop_fade_length); rci->resize_preloop (loop_fade_length);
if (loc->start () > 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); audio_playlist ()->read (rci->pre_loop_buffer, mix_buf.get (), gain_buf.get (), read_start, read_cnt, channel);
} else { } else {
memset (rci->pre_loop_buffer, 0, sizeof (Sample) * loop_fade_length); memset (rci->pre_loop_buffer, 0, sizeof (Sample) * loop_fade_length);
} }

View file

@ -169,12 +169,13 @@ DiskWriter::check_record_status (samplepos_t transport_sample, double speed, boo
Location* loc; Location* loc;
if (_session.config.get_punch_in () && 0 != (loc = _session.locations()->auto_punch_location ())) { if (_session.config.get_punch_in () && 0 != (loc = _session.locations()->auto_punch_location ())) {
_capture_start_sample = loc->start (); _capture_start_sample = loc->start_sample ();
} else if (_loop_location) { } else if (_loop_location) {
_capture_start_sample = _loop_location->start (); _capture_start_sample = _loop_location->start_sample ();
if (_last_possibly_recording & transport_rolling) { if (_last_possibly_recording & transport_rolling) {
_accumulated_capture_offset = _playback_offset + transport_sample - _session.transport_sample (); // + rec_offset; _accumulated_capture_offset = _playback_offset + transport_sample - _session.transport_sample (); // + rec_offset;
} }
} else { } else {
_capture_start_sample = _session.transport_sample (); _capture_start_sample = _session.transport_sample ();
} }
@ -191,7 +192,7 @@ DiskWriter::check_record_status (samplepos_t transport_sample, double speed, boo
* We should allow to move it or at least allow to disable punch-out * We should allow to move it or at least allow to disable punch-out
* while rolling.. * while rolling..
*/ */
_last_recordable_sample = loc->end (); _last_recordable_sample = loc->end_sample ();
if (_alignment_style == ExistingMaterial) { if (_alignment_style == ExistingMaterial) {
_last_recordable_sample += _capture_offset + _playback_offset; _last_recordable_sample += _capture_offset + _playback_offset;
} }
@ -234,14 +235,14 @@ DiskWriter::check_record_status (samplepos_t transport_sample, double speed, boo
} }
void 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 (Temporal::OverlapType ot, samplepos_t transport_sample, samplecnt_t nframes, samplecnt_t & rec_nframes, samplecnt_t & rec_offset)
{ {
switch (ot) { switch (ot) {
case Evoral::OverlapNone: case Temporal::OverlapNone:
rec_nframes = 0; rec_nframes = 0;
break; break;
case Evoral::OverlapInternal: case Temporal::OverlapInternal:
/* ---------- recrange /* ---------- recrange
* |---| transrange * |---| transrange
*/ */
@ -249,7 +250,7 @@ DiskWriter::calculate_record_range (Evoral::OverlapType ot, samplepos_t transpor
rec_offset = 0; rec_offset = 0;
break; break;
case Evoral::OverlapStart: case Temporal::OverlapStart:
/* |--------| recrange /* |--------| recrange
* -----| transrange * -----| transrange
*/ */
@ -259,7 +260,7 @@ DiskWriter::calculate_record_range (Evoral::OverlapType ot, samplepos_t transpor
} }
break; break;
case Evoral::OverlapEnd: case Temporal::OverlapEnd:
/* |--------| recrange /* |--------| recrange
* |-------- transrange * |-------- transrange
*/ */
@ -267,7 +268,7 @@ DiskWriter::calculate_record_range (Evoral::OverlapType ot, samplepos_t transpor
rec_offset = 0; rec_offset = 0;
break; break;
case Evoral::OverlapExternal: case Temporal::OverlapExternal:
/* |--------| recrange /* |--------| recrange
* -------------- transrange * -------------- transrange
*/ */
@ -394,7 +395,8 @@ void
DiskWriter::non_realtime_locate (samplepos_t position) DiskWriter::non_realtime_locate (samplepos_t position)
{ {
if (_midi_write_source) { if (_midi_write_source) {
_midi_write_source->set_natural_position (position); #warning NUTEMPO maybe fixme perhaps take sources time domain into account here e.g. beats
_midi_write_source->set_natural_position (timepos_t (position));
} }
DiskIOProcessor::non_realtime_locate (position); DiskIOProcessor::non_realtime_locate (position);
@ -430,14 +432,14 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
bool re = record_enabled (); bool re = record_enabled ();
bool punch_in = _session.config.get_punch_in () && _session.locations()->auto_punch_location (); bool punch_in = _session.config.get_punch_in () && _session.locations()->auto_punch_location ();
bool can_record = _session.actively_recording (); bool can_record = _session.actively_recording ();
can_record |= speed != 0 && _session.get_record_enabled () && punch_in && _session.transport_sample () <= _session.locations()->auto_punch_location ()->start (); can_record |= speed != 0 && _session.get_record_enabled () && punch_in && _session.transport_sample () <= _session.locations()->auto_punch_location ()->start_sample ();
_need_butler = false; _need_butler = false;
const Location* const loop_loc = _loop_location; const Location* const loop_loc = _loop_location;
samplepos_t loop_start = 0; timepos_t loop_start;
samplepos_t loop_end = 0; timepos_t loop_end;
samplepos_t loop_length = 0; timecnt_t loop_length;
if (_transport_looped && _capture_captured == 0) { if (_transport_looped && _capture_captured == 0) {
_transport_looped = false; _transport_looped = false;
@ -446,9 +448,9 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
if (loop_loc) { if (loop_loc) {
get_location_times (loop_loc, &loop_start, &loop_end, &loop_length); get_location_times (loop_loc, &loop_start, &loop_end, &loop_length);
if (_was_recording && _transport_looped && _capture_captured >= loop_length) { if (_was_recording && _transport_looped && _capture_captured >= loop_length.samples()) {
samplecnt_t remain = _capture_captured - loop_length; samplecnt_t remain = _capture_captured - loop_length.samples();
_capture_captured = loop_length; _capture_captured = loop_length.samples();
loop (_transport_loop_sample); loop (_transport_loop_sample);
_capture_captured = remain; _capture_captured = remain;
} }
@ -481,7 +483,7 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
if (nominally_recording || (re && _was_recording && _session.get_record_enabled() && punch_in)) { 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); Temporal::OverlapType ot = Temporal::coverage_exclusive_ends (_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 // XXX should this be transport_sample + nframes - 1 ? coverage() expects its parameter ranges to include their end points
// XXX also, first_recordable_sample & last_recordable_sample may both be == max_samplepos: coverage() will return OverlapNone in that case. Is thak OK? // XXX also, first_recordable_sample & last_recordable_sample may both be == max_samplepos: coverage() will return OverlapNone in that case. Is thak OK?
calculate_record_range (ot, start_sample, nframes, rec_nframes, rec_offset); calculate_record_range (ot, start_sample, nframes, rec_nframes, rec_offset);
@ -498,9 +500,10 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
at the loop start and can handle time wrapping around. at the loop start and can handle time wrapping around.
Otherwise, start the source right now as usual. Otherwise, start the source right now as usual.
*/ */
_capture_captured = start_sample - loop_start + rec_offset;
_capture_start_sample = loop_start; _capture_captured = start_sample - loop_start.samples() + rec_offset;
_first_recordable_sample = loop_start; _capture_start_sample = loop_start.samples();
_first_recordable_sample = loop_start.samples();
if (_alignment_style == ExistingMaterial) { if (_alignment_style == ExistingMaterial) {
_capture_captured -= _playback_offset + _capture_offset; _capture_captured -= _playback_offset + _capture_offset;
@ -521,7 +524,7 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
if (_midi_write_source) { if (_midi_write_source) {
assert (_capture_start_sample); assert (_capture_start_sample);
_midi_write_source->mark_write_starting_now (_capture_start_sample.value (), _capture_captured, loop_length); _midi_write_source->mark_write_starting_now (_capture_start_sample, _capture_captured, loop_length.samples());
} }
g_atomic_int_set (&_samples_pending_write, 0); g_atomic_int_set (&_samples_pending_write, 0);
@ -629,7 +632,7 @@ DiskWriter::run (BufferSet& bufs, samplepos_t start_sample, samplepos_t end_samp
reconstruct their actual time; future clever MIDI looping should reconstruct their actual time; future clever MIDI looping should
probably be implemented in the source instead of here. probably be implemented in the source instead of here.
*/ */
const samplecnt_t loop_offset = g_atomic_int_get (&_num_captured_loops) * loop_length; const samplecnt_t loop_offset = g_atomic_int_get (&_num_captured_loops) * loop_length.samples();
const samplepos_t event_time = start_sample + loop_offset - _accumulated_capture_offset + ev.time(); const samplepos_t event_time = start_sample + loop_offset - _accumulated_capture_offset + ev.time();
if (event_time < 0 || event_time < _first_recordable_sample) { if (event_time < 0 || event_time < _first_recordable_sample) {
/* Event out of range, skip */ /* Event out of range, skip */
@ -743,11 +746,11 @@ DiskWriter::finish_capture (boost::shared_ptr<ChannelList> c)
_xruns.clear (); _xruns.clear ();
if (_loop_location) { if (_loop_location) {
samplepos_t loop_start = 0; timepos_t loop_start;
samplepos_t loop_end = 0; timepos_t loop_end;
samplepos_t loop_length = 0; timecnt_t loop_length;
get_location_times (_loop_location, &loop_start, &loop_end, &loop_length); get_location_times (_loop_location, &loop_start, &loop_end, &loop_length);
ci->loop_offset = g_atomic_int_get (&_num_captured_loops) * loop_length; ci->loop_offset = g_atomic_int_get (&_num_captured_loops) * loop_length.samples();
} else { } else {
ci->loop_offset = 0; ci->loop_offset = 0;
} }
@ -1021,7 +1024,7 @@ DiskWriter::do_flush (RunContext ctxt, bool force_flush)
if ((total > _chunk_samples) || force_flush) { if ((total > _chunk_samples) || force_flush) {
Source::Lock lm(_midi_write_source->mutex()); Source::Lock lm(_midi_write_source->mutex());
if (_midi_write_source->midi_write (lm, *_midi_buf, get_capture_start_sample (0), to_write) != to_write) { if (_midi_write_source->midi_write (lm, *_midi_buf, timepos_t (get_capture_start_sample (0)), timecnt_t (to_write)) != to_write) {
error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg; error << string_compose(_("MidiDiskstream %1: cannot write to disk"), id()) << endmsg;
return -1; return -1;
} }
@ -1221,7 +1224,7 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo
Analyser::queue_source_for_analysis (as, true); Analyser::queue_source_for_analysis (as, true);
} }
DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("newly captured source %1 length %2\n", as->path(), as->length (0))); DEBUG_TRACE (DEBUG::CaptureAlignment, string_compose ("newly captured source %1 length %2\n", as->path(), as->length ()));
} }
if (_midi_write_source) { if (_midi_write_source) {
@ -1238,7 +1241,7 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo
if (_midi_write_source) { if (_midi_write_source) {
if (_midi_write_source->length (capture_info.front()->start) == 0) { if (_midi_write_source->empty()) {
/* No data was recorded, so this capture will /* No data was recorded, so this capture will
effectively be aborted; do the same as we effectively be aborted; do the same as we
do for an explicit abort. do for an explicit abort.
@ -1260,27 +1263,17 @@ DiskWriter::transport_stopped_wallclock (struct tm& when, time_t twhen, bool abo
midi_srcs.push_back (_midi_write_source); midi_srcs.push_back (_midi_write_source);
_midi_write_source->set_natural_position (capture_info.front()->start); _midi_write_source->set_natural_position (timepos_t (capture_info.front()->start));
_midi_write_source->set_captured_for (_track.name ()); _midi_write_source->set_captured_for (_track.name());
Glib::DateTime tm (Glib::DateTime::create_now_local (mktime (&when))); Glib::DateTime tm (Glib::DateTime::create_now_local (mktime (&when)));
_midi_write_source->set_take_id (tm.format ("%F %H.%M.%S")); _midi_write_source->set_take_id (tm.format ("%F %H.%M.%S"));
/* set length in beats to entire capture length */
Temporal::Beats total_capture_beats;
for (vector<CaptureInfo*>::iterator ci = capture_info.begin(); ci != capture_info.end(); ++ci) {
BeatsSamplesConverter converter (_session.tempo_map(), (*ci)->start);
total_capture_beats += converter.from ((*ci)->samples);
}
_midi_write_source->set_length_beats (total_capture_beats);
/* flush to disk: this step differs from the audio path, /* flush to disk: this step differs from the audio path,
where all the data is already on disk. where all the data is already on disk.
*/ */
_midi_write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Temporal::Beats>::ResolveStuckNotes, total_capture_beats); _midi_write_source->mark_midi_streaming_write_completed (source_lock, Evoral::Sequence<Temporal::Beats>::ResolveStuckNotes, timecnt_t (total_capture, timepos_t (capture_info.front()->start)).beats());
} }
_last_capture_sources.insert (_last_capture_sources.end(), audio_srcs.begin(), audio_srcs.end()); _last_capture_sources.insert (_last_capture_sources.end(), audio_srcs.begin(), audio_srcs.end());

View file

@ -42,7 +42,7 @@ EBUr128Analysis::~EBUr128Analysis()
} }
int int
EBUr128Analysis::run (Readable* src) EBUr128Analysis::run (AudioReadable* src)
{ {
int ret = -1; int ret = -1;
bool done = false; bool done = false;

View file

@ -29,8 +29,6 @@
#include "pbd/enumwriter.h" #include "pbd/enumwriter.h"
#include "midi++/types.h" #include "midi++/types.h"
#include "evoral/Range.h" // shouldn't Evoral have its own enum registration?
#include "ardour/delivery.h" #include "ardour/delivery.h"
#include "ardour/disk_io.h" #include "ardour/disk_io.h"
#include "ardour/export_channel.h" #include "ardour/export_channel.h"
@ -146,7 +144,6 @@ setup_enum_writer ()
ScreenSaverMode _ScreenSaverMode; ScreenSaverMode _ScreenSaverMode;
Session::PostTransportWork _Session_PostTransportWork; Session::PostTransportWork _Session_PostTransportWork;
MTC_Status _MIDI_MTC_Status; MTC_Status _MIDI_MTC_Status;
Evoral::OverlapType _OverlapType;
BufferingPreset _BufferingPreset; BufferingPreset _BufferingPreset;
AutoReturnTarget _AutoReturnTarget; AutoReturnTarget _AutoReturnTarget;
PresentationInfo::Flag _PresentationInfo_Flag; PresentationInfo::Flag _PresentationInfo_Flag;
@ -743,13 +740,6 @@ setup_enum_writer ()
REGISTER_ENUM(MusicTime); REGISTER_ENUM(MusicTime);
REGISTER(_PositionLockStyle); REGISTER(_PositionLockStyle);
REGISTER_ENUM (Evoral::OverlapNone);
REGISTER_ENUM (Evoral::OverlapInternal);
REGISTER_ENUM (Evoral::OverlapStart);
REGISTER_ENUM (Evoral::OverlapEnd);
REGISTER_ENUM (Evoral::OverlapExternal);
REGISTER(_OverlapType);
REGISTER_ENUM (Small); REGISTER_ENUM (Small);
REGISTER_ENUM (Medium); REGISTER_ENUM (Medium);
REGISTER_ENUM (Large); REGISTER_ENUM (Large);

View file

@ -174,7 +174,7 @@ RegionExportChannelFactory::RegionExportChannelFactory (Session * session, Audio
, type (type) , type (type)
, samples_per_cycle (session->engine().samples_per_cycle ()) , samples_per_cycle (session->engine().samples_per_cycle ())
, buffers_up_to_date (false) , buffers_up_to_date (false)
, region_start (region.position()) , region_start (region.position_sample())
, position (region_start) , position (region_start)
{ {
switch (type) { switch (type) {

View file

@ -598,7 +598,7 @@ ExportHandler::export_cd_marker_file (ExportTimespanPtr timespan, ExportFormatSp
if ((*i)->is_mark()) { if ((*i)->is_mark()) {
/* Index within track */ /* Index within track */
status.index_position = (*i)->start() - timespan->get_start(); status.index_position = (*i)->start_sample() - timespan->get_start();
(this->*index_func) (status); (this->*index_func) (status);
} }
@ -608,7 +608,7 @@ ExportHandler::export_cd_marker_file (ExportTimespanPtr timespan, ExportFormatSp
/* A track, defined by a cd range marker or a cd location marker outside of a cd range */ /* A track, defined by a cd range marker or a cd location marker outside of a cd range */
status.track_position = last_end_time - timespan->get_start(); status.track_position = last_end_time - timespan->get_start();
status.track_start_sample = (*i)->start() - timespan->get_start(); // everything before this is the pregap status.track_start_sample = (*i)->start_sample() - timespan->get_start(); // everything before this is the pregap
status.track_duration = 0; status.track_duration = 0;
if ((*i)->is_mark()) { if ((*i)->is_mark()) {
@ -617,9 +617,9 @@ ExportHandler::export_cd_marker_file (ExportTimespanPtr timespan, ExportFormatSp
++nexti; ++nexti;
if (nexti != temp.end()) { if (nexti != temp.end()) {
status.track_duration = (*nexti)->start() - last_end_time; status.track_duration = (*nexti)->start_sample() - last_end_time;
last_end_time = (*nexti)->start(); last_end_time = (*nexti)->start_sample();
} else { } else {
// this was the last marker, use timespan end // this was the last marker, use timespan end
status.track_duration = timespan->get_end() - last_end_time; status.track_duration = timespan->get_end() - last_end_time;
@ -628,9 +628,9 @@ ExportHandler::export_cd_marker_file (ExportTimespanPtr timespan, ExportFormatSp
} }
} else { } else {
// range // range
status.track_duration = (*i)->end() - last_end_time; status.track_duration = (*i)->end_sample() - last_end_time;
last_end_time = (*i)->end(); last_end_time = (*i)->end_sample();
} }
(this->*track_func) (status); (this->*track_func) (status);

View file

@ -363,7 +363,7 @@ ExportProfileManager::set_selection_range (samplepos_t start, samplepos_t end)
if (start || end) { if (start || end) {
selection_range.reset (new Location (session)); selection_range.reset (new Location (session));
selection_range->set_name (_("Selection")); selection_range->set_name (_("Selection"));
selection_range->set (start, end); selection_range->set (timepos_t (start), timepos_t (end));
} else { } else {
selection_range.reset(); selection_range.reset();
} }
@ -380,7 +380,7 @@ ExportProfileManager::set_single_range (samplepos_t start, samplepos_t end, stri
single_range.reset (new Location (session)); single_range.reset (new Location (session));
single_range->set_name (name); single_range->set_name (name);
single_range->set (start, end); single_range->set (timepos_t (start), timepos_t (end));
update_ranges (); update_ranges ();
@ -415,7 +415,7 @@ ExportProfileManager::init_timespans (XMLNodeList nodes)
ExportTimespanPtr timespan = handler->add_timespan(); ExportTimespanPtr timespan = handler->add_timespan();
timespan->set_name (session_range->name()); timespan->set_name (session_range->name());
timespan->set_range_id (session_range->id().to_s()); timespan->set_range_id (session_range->id().to_s());
timespan->set_range (session_range->start(), session_range->end()); timespan->set_range (session_range->start_sample(), session_range->end_sample());
state->timespans->push_back (timespan); state->timespans->push_back (timespan);
return false; return false;
} }
@ -450,7 +450,7 @@ ExportProfileManager::deserialize_timespan (XMLNode & root)
ExportTimespanPtr timespan = handler->add_timespan(); ExportTimespanPtr timespan = handler->add_timespan();
timespan->set_name (location->name()); timespan->set_name (location->name());
timespan->set_range_id (location->id().to_s()); timespan->set_range_id (location->id().to_s());
timespan->set_range (location->start(), location->end()); timespan->set_range (location->start_sample(), location->end_sample());
state->timespans->push_back (timespan); state->timespans->push_back (timespan);
} }

View file

@ -43,9 +43,10 @@ int
Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs, std::string suffix, bool use_session_sample_rate) Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs, std::string suffix, bool use_session_sample_rate)
{ {
vector<string> names = region->master_source_names(); vector<string> names = region->master_source_names();
assert (region->n_channels() <= names.size()); const SourceList::size_type nsrc = region->sources().size();
assert (nsrc <= names.size());
for (uint32_t i = 0; i < region->n_channels(); ++i) { for (SourceList::size_type i = 0; i < nsrc; ++i) {
string name = PBD::basename_nosuffix (names[i]); string name = PBD::basename_nosuffix (names[i]);
@ -62,7 +63,7 @@ Filter::make_new_sources (boost::shared_ptr<Region> region, SourceList& nsrcs, s
const string path = (region->data_type() == DataType::MIDI) const string path = (region->data_type() == DataType::MIDI)
? session.new_midi_source_path (name) ? session.new_midi_source_path (name)
: session.new_audio_source_path (name, region->n_channels(), i, false); : session.new_audio_source_path (name, nsrc, i, false);
if (path.empty()) { if (path.empty()) {
error << string_compose (_("filter: error creating name for new file based on %1"), region->name()) error << string_compose (_("filter: error creating name for new file based on %1"), region->name())
@ -120,7 +121,7 @@ Filter::finish (boost::shared_ptr<Region> region, SourceList& nsrcs, string regi
boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource>(*si); boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource>(*si);
if (smfs) { if (smfs) {
smfs->set_natural_position (region->position_sample()); smfs->set_natural_position (region->nt_position());
smfs->flush (); smfs->flush ();
} }
@ -138,7 +139,7 @@ Filter::finish (boost::shared_ptr<Region> region, SourceList& nsrcs, string regi
PropertyList plist; PropertyList plist;
plist.add (Properties::start, 0); plist.add (Properties::start, std::numeric_limits<timecnt_t>::min());
plist.add (Properties::length, region->nt_length()); plist.add (Properties::length, region->nt_length());
plist.add (Properties::name, region_name); plist.add (Properties::name, region_name);
plist.add (Properties::whole_file, true); plist.add (Properties::whole_file, true);

View file

@ -63,7 +63,7 @@ static boost::shared_ptr<AutomationList> automation_list_new (Evoral::Parameter
case BusSendLevel: case BusSendLevel:
/* fallthrough */ /* fallthrough */
case TrimAutomation: case TrimAutomation:
return boost::shared_ptr<AutomationList> (new AutomationList (param)); return boost::shared_ptr<AutomationList> (new AutomationList (param, Temporal::AudioTime));
case MainOutVolume: case MainOutVolume:
/* not automatable */ /* not automatable */
break; break;
@ -112,10 +112,10 @@ bool
GainControl::get_masters_curve_locked (samplepos_t start, samplepos_t end, float* vec, samplecnt_t veclen) const GainControl::get_masters_curve_locked (samplepos_t start, samplepos_t end, float* vec, samplecnt_t veclen) const
{ {
if (_masters.empty()) { if (_masters.empty()) {
return list()->curve().rt_safe_get_vector (start, end, vec, veclen); return list()->curve().rt_safe_get_vector (timepos_t (start), timepos_t (end), vec, veclen);
} }
for (samplecnt_t i = 0; i < veclen; ++i) { for (samplecnt_t i = 0; i < veclen; ++i) {
vec[i] = 1.f; vec[i] = 1.f;
} }
return SlavableAutomationControl::masters_curve_multiply (start, end, vec, veclen); return SlavableAutomationControl::masters_curve_multiply (timepos_t (start), timepos_t (end), vec, veclen);
} }

View file

@ -539,6 +539,8 @@ ARDOUR::init (bool try_optimization, const char* localedir, bool with_gui)
if (!PBD::init ()) if (!PBD::init ())
return false; return false;
Temporal::init ();
#if ENABLE_NLS #if ENABLE_NLS
(void)bindtextdomain (PACKAGE, localedir); (void)bindtextdomain (PACKAGE, localedir);
(void)bind_textdomain_codeset (PACKAGE, "UTF-8"); (void)bind_textdomain_codeset (PACKAGE, "UTF-8");

View file

@ -231,7 +231,7 @@ create_mono_sources_for_writing (const vector<string>& new_paths,
boost::shared_ptr<AudioFileSource> afs; boost::shared_ptr<AudioFileSource> afs;
if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) { if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
afs->set_natural_position (natural_position); afs->set_natural_position (timepos_t (natural_position));
} }
} }
return true; return true;
@ -462,8 +462,7 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
const samplepos_t pos = 0; const samplepos_t pos = 0;
const Temporal::Beats length_beats = Temporal::Beats::ticks_at_rate(t, source->ppqn()); const Temporal::Beats length_beats = Temporal::Beats::ticks_at_rate(t, source->ppqn());
BeatsSamplesConverter converter(smfs->session().tempo_map(), pos); smfs->update_length (timecnt_t (length_beats.round_up_to_beat(), timepos_t(Temporal::BeatTime)));
smfs->update_length(pos + converter.to(length_beats.round_up_to_beat()));
smfs->mark_streaming_write_completed (source_lock); smfs->mark_streaming_write_completed (source_lock);
if (status.cancel) { if (status.cancel) {
@ -618,7 +617,7 @@ Session::import_files (ImportStatus& status)
for (Sources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ) { for (Sources::iterator x = all_new_sources.begin(); x != all_new_sources.end(); ) {
if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*x)) != 0) { if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(*x)) != 0) {
afs->update_header((*x)->natural_position(), *now, xnow); afs->update_header((*x)->natural_position().samples(), *now, xnow);
afs->done_with_peakfile_writes (); afs->done_with_peakfile_writes ();
/* now that there is data there, requeue the file for analysis */ /* now that there is data there, requeue the file for analysis */

View file

@ -75,7 +75,7 @@ struct PlaylistState {
}; };
bool bool
Session::import_sndfile_as_region (string path, SrcQuality quality, samplepos_t& pos, SourceList& sources, ImportStatus& status, uint32_t current, uint32_t total) Session::import_sndfile_as_region (string path, SrcQuality quality, timepos_t& pos, SourceList& sources, ImportStatus& status, uint32_t current, uint32_t total)
{ {
/* Import the source */ /* Import the source */
status.paths.clear(); status.paths.clear();
@ -113,7 +113,7 @@ Session::import_sndfile_as_region (string path, SrcQuality quality, samplepos_t&
string region_name; string region_name;
bool use_timestamp; bool use_timestamp;
use_timestamp = (pos == -1); use_timestamp = (pos == timepos_t::max (Temporal::AudioTime));
/* take all the sources we have and package them up as a region */ /* take all the sources we have and package them up as a region */
@ -127,8 +127,8 @@ Session::import_sndfile_as_region (string path, SrcQuality quality, samplepos_t&
PropertyList plist; PropertyList plist;
plist.add (ARDOUR::Properties::start, 0); plist.add (ARDOUR::Properties::start, timepos_t (0));
plist.add (ARDOUR::Properties::length, sources[0]->length (pos)); plist.add (ARDOUR::Properties::length, timecnt_t (sources[0]->length (), pos));
plist.add (ARDOUR::Properties::name, region_name); plist.add (ARDOUR::Properties::name, region_name);
plist.add (ARDOUR::Properties::layer, 0); plist.add (ARDOUR::Properties::layer, 0);
plist.add (ARDOUR::Properties::whole_file, true); plist.add (ARDOUR::Properties::whole_file, true);
@ -164,11 +164,11 @@ Session::import_sndfile_as_region (string path, SrcQuality quality, samplepos_t&
if (as->natural_position() != 0) { if (as->natural_position() != 0) {
pos = as->natural_position(); pos = as->natural_position();
} else { } else {
pos = 0; pos = timepos_t (pos.time_domain ());
} }
} else { } else {
/* should really get first position in MIDI file, but for now, use 0 */ /* should really get first position in MIDI file, but for now, use 0 */
pos = 0; pos = timepos_t (pos.time_domain());
} }
} }
} }
@ -187,7 +187,8 @@ Session::import_pt_sources (PTFFormat& ptf, ImportStatus& status)
string fullpath; string fullpath;
bool ok = false; bool ok = false;
bool onefailed = false; bool onefailed = false;
samplepos_t pos = -1; timepos_t pos = timepos_t::max (Temporal::AudioTime);
uint32_t srate = sample_rate ();
vector<PTFFormat::wav_t>::const_iterator w; vector<PTFFormat::wav_t>::const_iterator w;
uint32_t wth = 0; uint32_t wth = 0;
@ -376,12 +377,42 @@ Session::import_pt_rest (PTFFormat& ptf)
/* Matched a ptf active region to an ardour region */ /* Matched a ptf active region to an ardour region */
boost::shared_ptr<Region> r = RegionFactory::region_by_id (p->id); boost::shared_ptr<Region> r = RegionFactory::region_by_id (p->id);
DEBUG_TRACE (DEBUG::FileUtils, string_compose ("\twav(%1) reg(%2) tr(%3)\n", a->reg.wave.filename.c_str (), a->reg.index, a->index)); vector<struct ptflookup>::iterator lookuptr = usedtracks.begin ();
vector<struct ptflookup>::iterator found;
if ((found = std::find (lookuptr, usedtracks.end (), utr)) != usedtracks.end ()) {
DEBUG_TRACE (DEBUG::FileUtils, string_compose ("\twav(%1) reg(%2) ptf_tr(%3) ard_tr(%4)\n", a->reg.wave.filename.c_str (), a->reg.index, found->index1, found->index2));
/* Use existing playlists */ /* Use existing track if possible */
boost::shared_ptr<Playlist> playlist = playlists[a->index].playlist; existing_track = get_nth_audio_track (found->index2 + 1);
boost::shared_ptr<Region> copy (RegionFactory::create (r, true)); if (!existing_track) {
playlist->add_region (copy, a->reg.startpos); list<boost::shared_ptr<AudioTrack> > at (new_audio_track (1, 2, 0, 1, a->name.c_str(), PresentationInfo::max_order, Normal));
if (at.empty ()) {
return;
}
existing_track = at.back ();
}
/* Put on existing track */
boost::shared_ptr<Playlist> playlist = existing_track->playlist ();
boost::shared_ptr<Region> copy (RegionFactory::create (r, true));
playlist->clear_changes ();
playlist->add_region (copy, timepos_t (a->reg.startpos));
//add_command (new StatefulDiffCommand (playlist));
} else {
/* Put on a new track */
DEBUG_TRACE (DEBUG::FileUtils, string_compose ("\twav(%1) reg(%2) new_tr(%3)\n", a->reg.wave.filename.c_str (), a->reg.index, nth));
list<boost::shared_ptr<AudioTrack> > at (new_audio_track (1, 2, 0, 1, a->name.c_str(), PresentationInfo::max_order, Normal));
if (at.empty ()) {
return;
}
existing_track = at.back ();
boost::shared_ptr<Playlist> playlist = existing_track->playlist();
boost::shared_ptr<Region> copy (RegionFactory::create (r, true));
playlist->clear_changes ();
playlist->add_region (copy, timepos_t (a->reg.startpos));
//add_command (new StatefulDiffCommand (playlist));
nth++;
usedtracks.push_back (utr);
}
} }
} }
} }
@ -442,9 +473,9 @@ no_audio_tracks:
plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix (src->name ())); plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix (src->name ()));
//printf(" : %d - trackname: (%s)\n", a->index, src->name ().c_str ()); //printf(" : %d - trackname: (%s)\n", a->index, src->name ().c_str ());
boost::shared_ptr<Region> region = (RegionFactory::create (src, plist)); boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
/* sets beat position */ /* sets position */
region->set_position (pos.sample, pos.division); region->set_position (timepos_t (pos.sample));
midi_track->playlist ()->add_region (region, pos.sample, 1.0, false, pos.division); midi_track->playlist ()->add_region (region, timepos_t (pos.sample), 1.0, false);
boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region); boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
boost::shared_ptr<MidiModel> mm = mr->midi_source (0)->model (); boost::shared_ptr<MidiModel> mm = mr->midi_source (0)->model ();
@ -461,6 +492,6 @@ no_audio_tracks:
mm->apply_command (this, midicmd); mm->apply_command (this, midicmd);
boost::shared_ptr<Region> copy (RegionFactory::create (mr, true)); boost::shared_ptr<Region> copy (RegionFactory::create (mr, true));
playlist->clear_changes (); playlist->clear_changes ();
playlist->add_region (copy, f); playlist->add_region (copy, timepos_t (f));
} }
} }

View file

@ -53,6 +53,7 @@ namespace PBD {
using namespace std; using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
using namespace Temporal;
PBD::Signal0<void> Location::scene_changed; PBD::Signal0<void> Location::scene_changed;
PBD::Signal1<void,Location*> Location::name_changed; PBD::Signal1<void,Location*> Location::name_changed;
@ -60,39 +61,32 @@ PBD::Signal1<void,Location*> Location::end_changed;
PBD::Signal1<void,Location*> Location::start_changed; PBD::Signal1<void,Location*> Location::start_changed;
PBD::Signal1<void,Location*> Location::flags_changed; PBD::Signal1<void,Location*> Location::flags_changed;
PBD::Signal1<void,Location*> Location::lock_changed; PBD::Signal1<void,Location*> Location::lock_changed;
PBD::Signal1<void,Location*> Location::position_lock_style_changed;
PBD::Signal1<void,Location*> Location::changed; PBD::Signal1<void,Location*> Location::changed;
Location::Location (Session& s) Location::Location (Session& s)
: SessionHandleRef (s) : SessionHandleRef (s)
, _start (0)
, _start_beat (0.0)
, _end (0)
, _end_beat (0.0)
, _flags (Flags (0)) , _flags (Flags (0))
, _locked (false) , _locked (false)
, _position_lock_style (AudioTime)
, _timestamp (time (0)) , _timestamp (time (0))
{ {
assert (_start >= 0);
assert (_end >= 0);
} }
/** Construct a new Location, giving it the position lock style determined by glue-new-markers-to-bars-and-beats */ /** Construct a new Location, giving it the position lock style determined by glue-new-markers-to-bars-and-beats */
Location::Location (Session& s, samplepos_t sample_start, samplepos_t sample_end, const std::string &name, Flags bits, const uint32_t sub_num) Location::Location (Session& s, timepos_t const & start, timepos_t const & end, const std::string &name, Flags bits)
: SessionHandleRef (s) : SessionHandleRef (s)
, _name (name) , _name (name)
, _start (sample_start) , _start (start)
, _end (sample_end) , _end (end)
, _flags (bits) , _flags (bits)
, _locked (false) , _locked (false)
, _position_lock_style (s.config.get_glue_new_markers_to_bars_and_beats() ? MusicTime : AudioTime)
, _timestamp (time (0)) , _timestamp (time (0))
{ {
recompute_beat_from_samples (sub_num); #warning NUTEMPO FIXME drop this and ensure that timepos start/end use correct domain in caller for this constructor
if (s.config.get_glue_new_markers_to_bars_and_beats()) {
assert (_start >= 0); set_position_time_domain (Temporal::BeatTime);
assert (_end >= 0); } else {
set_position_time_domain (Temporal::AudioTime);
}
} }
Location::Location (const Location& other) Location::Location (const Location& other)
@ -100,39 +94,32 @@ Location::Location (const Location& other)
, StatefulDestructible() , StatefulDestructible()
, _name (other._name) , _name (other._name)
, _start (other._start) , _start (other._start)
, _start_beat (other._start_beat)
, _end (other._end) , _end (other._end)
, _end_beat (other._end_beat)
, _flags (other._flags) , _flags (other._flags)
, _position_lock_style (other._position_lock_style)
, _timestamp (time (0)) , _timestamp (time (0))
{ {
/* copy is not locked even if original was */ /* copy is not locked even if original was */
_locked = false; _locked = false;
assert (_start >= 0);
assert (_end >= 0);
/* scene change is NOT COPIED */ /* scene change is NOT COPIED */
} }
Location::Location (Session& s, const XMLNode& node) Location::Location (Session& s, const XMLNode& node)
: SessionHandleRef (s) : SessionHandleRef (s)
, _flags (Flags (0)) , _flags (Flags (0))
, _position_lock_style (AudioTime)
, _timestamp (time (0)) , _timestamp (time (0))
{ {
/* Note: _position_lock_style is initialised above in case set_state doesn't set it //_start.set_time_domain (AudioTime);
(for 2.X session file compatibility). //_end.set_time_domain (AudioTime);
*/
/* Note: _position_time_domain is initialised above in case set_state
* doesn't set it
*/
if (set_state (node, Stateful::loading_state_version)) { if (set_state (node, Stateful::loading_state_version)) {
throw failed_constructor (); throw failed_constructor ();
} }
assert (_start >= 0);
assert (_end >= 0);
} }
bool bool
@ -141,10 +128,7 @@ Location::operator== (const Location& other)
if (_name != other._name || if (_name != other._name ||
_start != other._start || _start != other._start ||
_end != other._end || _end != other._end ||
_start_beat != other._start_beat || _flags != other._flags) {
_end_beat != other._end_beat ||
_flags != other._flags ||
_position_lock_style != other._position_lock_style) {
return false; return false;
} }
return true; return true;
@ -159,11 +143,8 @@ Location::operator= (const Location& other)
_name = other._name; _name = other._name;
_start = other._start; _start = other._start;
_start_beat = other._start_beat;
_end = other._end; _end = other._end;
_end_beat = other._end_beat;
_flags = other._flags; _flags = other._flags;
_position_lock_style = other._position_lock_style;
/* XXX need to copy scene change */ /* XXX need to copy scene change */
@ -173,9 +154,6 @@ Location::operator= (const Location& other)
/* "changed" not emitted on purpose */ /* "changed" not emitted on purpose */
assert (_start >= 0);
assert (_end >= 0);
return this; return this;
} }
@ -194,14 +172,10 @@ Location::set_name (const std::string& str)
/** Set start position. /** Set start position.
* @param s New start. * @param s New start.
* @param force true to force setting, even if the given new start is after the current end. * @param force true to force setting, even if the given new start is after the current end.
* @param allow_beat_recompute True to recompute BEAT start time from the new given start time.
*/ */
int int
Location::set_start (samplepos_t s, bool force, bool allow_beat_recompute, const uint32_t sub_num) Location::set_start (Temporal::timepos_t const & s, bool force)
{ {
if (s < 0) {
return -1;
}
if (_locked) { if (_locked) {
return -1; return -1;
@ -217,9 +191,6 @@ Location::set_start (samplepos_t s, bool force, bool allow_beat_recompute, const
if (_start != s) { if (_start != s) {
_start = s; _start = s;
_end = s; _end = s;
if (allow_beat_recompute) {
recompute_beat_from_samples (sub_num);
}
start_changed (this); /* EMIT SIGNAL */ start_changed (this); /* EMIT SIGNAL */
StartChanged (); /* EMIT SIGNAL */ StartChanged (); /* EMIT SIGNAL */
@ -235,51 +206,42 @@ Location::set_start (samplepos_t s, bool force, bool allow_beat_recompute, const
scene_changed (); /* EMIT SIGNAL */ scene_changed (); /* EMIT SIGNAL */
} }
assert (_start >= 0); assert (s.zero() || s.positive());
assert (_end >= 0);
return 0; return 0;
} else if (!force) { } else if (!force) {
/* range locations must exceed a minimum duration */ /* range locations must exceed a minimum duration */
if (_end - s < Config->get_range_location_minimum()) { if (s.distance (_end) < Config->get_range_location_minimum()) {
return -1; return -1;
} }
} }
if (s != _start) { if (s != _start) {
samplepos_t const old = _start; Temporal::timepos_t const old = _start;
_start = s; _start = s;
if (allow_beat_recompute) {
recompute_beat_from_samples (sub_num);
}
start_changed (this); /* EMIT SIGNAL */ start_changed (this); /* EMIT SIGNAL */
StartChanged (); /* EMIT SIGNAL */ StartChanged (); /* EMIT SIGNAL */
if (is_session_range ()) { if (is_session_range ()) {
Session::StartTimeChanged (old); /* EMIT SIGNAL */ Session::StartTimeChanged (old.samples()); /* emit signal */
AudioFileSource::set_header_position_offset (s); AudioFileSource::set_header_position_offset (s.samples());
} }
} }
assert (_start >= 0); assert (_start.positive() || _start.zero());
return 0; return 0;
} }
/** Set end position. /** set end position.
* @param s New end. * @param s new end.
* @param force true to force setting, even if the given new end is before the current start. * @param force true to force setting, even if the given new end is before the current start.
* @param allow_beat_recompute True to recompute BEAT end time from the new given end time.
*/ */
int int
Location::set_end (samplepos_t e, bool force, bool allow_beat_recompute, const uint32_t sub_num) Location::set_end (Temporal::timepos_t const & e, bool force)
{ {
if (e < 0) {
return -1;
}
if (_locked) { if (_locked) {
return -1; return -1;
} }
@ -294,13 +256,10 @@ Location::set_end (samplepos_t e, bool force, bool allow_beat_recompute, const u
if (_start != e) { if (_start != e) {
_start = e; _start = e;
_end = e; _end = e;
if (allow_beat_recompute) { //start_changed (this); /* emit signal */
recompute_beat_from_samples (sub_num); //startchanged (); /* emit signal */
} end_changed (this); /* emit signal */
//start_changed (this); /* EMIT SIGNAL */ EndChanged (); /* emit signal */
//StartChanged (); /* EMIT SIGNAL */
end_changed (this); /* EMIT SIGNAL */
EndChanged (); /* EMIT SIGNAL */
} }
assert (_start >= 0); assert (_start >= 0);
@ -309,40 +268,32 @@ Location::set_end (samplepos_t e, bool force, bool allow_beat_recompute, const u
return 0; return 0;
} else if (!force) { } else if (!force) {
/* range locations must exceed a minimum duration */ /* range locations must exceed a minimum duration */
if (e - _start < Config->get_range_location_minimum()) { if (_start.distance (e) < Config->get_range_location_minimum()) {
return -1; return -1;
} }
} }
if (e != _end) { if (e != _end) {
samplepos_t const old = _end; timepos_t const old = _end;
_end = e; _end = e;
if (allow_beat_recompute) {
recompute_beat_from_samples (sub_num);
}
end_changed(this); /* EMIT SIGNAL */ end_changed(this); /* EMIT SIGNAL */
EndChanged(); /* EMIT SIGNAL */ EndChanged(); /* EMIT SIGNAL */
if (is_session_range()) { if (is_session_range()) {
Session::EndTimeChanged (old); /* EMIT SIGNAL */ Session::EndTimeChanged (old.samples()); /* EMIT SIGNAL */
} }
} }
assert (_end >= 0); assert (_end.positive() || _end.zero());
return 0; return 0;
} }
int int
Location::set (samplepos_t s, samplepos_t e, bool allow_beat_recompute, const uint32_t sub_num) Location::set (Temporal::timepos_t const & s, Temporal::timepos_t const & e)
{ {
if (s < 0 || e < 0) {
return -1;
}
/* check validity */ /* check validity */
if (((is_auto_punch() || is_auto_loop()) && s >= e) || (!is_mark() && s > e)) { if (((is_auto_punch() || is_auto_loop()) && s >= e) || (!is_mark() && s > e)) {
return -1; return -1;
@ -356,11 +307,6 @@ Location::set (samplepos_t s, samplepos_t e, bool allow_beat_recompute, const ui
if (_start != s) { if (_start != s) {
_start = s; _start = s;
_end = s; _end = s;
if (allow_beat_recompute) {
recompute_beat_from_samples (sub_num);
}
start_change = true; start_change = true;
end_change = true; end_change = true;
} }
@ -371,45 +317,35 @@ Location::set (samplepos_t s, samplepos_t e, bool allow_beat_recompute, const ui
} else { } else {
/* range locations must exceed a minimum duration */ /* range locations must exceed a minimum duration */
if (e - s < Config->get_range_location_minimum()) { if (s.distance (e) < Config->get_range_location_minimum()) {
return -1; return -1;
} }
if (s != _start) { if (s != _start) {
samplepos_t const old = _start; Temporal::timepos_t const old = _start;
_start = s; _start = s;
if (allow_beat_recompute) {
recompute_beat_from_samples (sub_num);
}
start_change = true; start_change = true;
if (is_session_range ()) { if (is_session_range ()) {
Session::StartTimeChanged (old); /* EMIT SIGNAL */ Session::StartTimeChanged (old.samples()); /* EMIT SIGNAL */
AudioFileSource::set_header_position_offset (s); AudioFileSource::set_header_position_offset (s.samples());
} }
} }
if (e != _end) { if (e != _end) {
samplepos_t const old = _end; Temporal::timepos_t const old = _end;
_end = e; _end = e;
if (allow_beat_recompute) {
recompute_beat_from_samples (sub_num);
}
end_change = true; end_change = true;
if (is_session_range()) { if (is_session_range()) {
Session::EndTimeChanged (old); /* EMIT SIGNAL */ Session::EndTimeChanged (old.samples()); /* EMIT SIGNAL */
} }
} }
assert (_end >= 0); assert (e.positive() || e.zero());
} }
if (start_change && end_change) { if (start_change && end_change) {
@ -427,20 +363,16 @@ Location::set (samplepos_t s, samplepos_t e, bool allow_beat_recompute, const ui
} }
int int
Location::move_to (samplepos_t pos, const uint32_t sub_num) Location::move_to (Temporal::timepos_t const & pos)
{ {
if (pos < 0) {
return -1;
}
if (_locked) { if (_locked) {
return -1; return -1;
} }
if (_start != pos) { if (_start != pos) {
const timecnt_t len = _start.distance (_end);
_start = pos; _start = pos;
_end = _start + length(); _end = pos + len;
recompute_beat_from_samples (sub_num);
changed (this); /* EMIT SIGNAL */ changed (this); /* EMIT SIGNAL */
Changed (); /* EMIT SIGNAL */ Changed (); /* EMIT SIGNAL */
@ -496,7 +428,7 @@ Location::set_is_clock_origin (bool yn, void*)
void void
Location::set_skip (bool yn) Location::set_skip (bool yn)
{ {
if (is_range_marker() && length() > 0) { if (is_range_marker() && length_samples() > 0) {
if (set_flag_internal (yn, IsSkip)) { if (set_flag_internal (yn, IsSkip)) {
flags_changed (this); flags_changed (this);
FlagsChanged (); FlagsChanged ();
@ -507,7 +439,7 @@ Location::set_skip (bool yn)
void void
Location::set_skipping (bool yn) Location::set_skipping (bool yn)
{ {
if (is_range_marker() && is_skip() && length() > 0) { if (is_range_marker() && is_skip() && length_samples() > 0) {
if (set_flag_internal (yn, IsSkipping)) { if (set_flag_internal (yn, IsSkipping)) {
flags_changed (this); flags_changed (this);
FlagsChanged (); FlagsChanged ();
@ -598,13 +530,8 @@ Location::get_state ()
node->set_property ("name", name()); node->set_property ("name", name());
node->set_property ("start", start()); node->set_property ("start", start());
node->set_property ("end", end()); node->set_property ("end", end());
if (position_lock_style() == MusicTime) {
node->set_property ("start-beat", _start_beat);
node->set_property ("end-beat", _end_beat);
}
node->set_property ("flags", _flags); node->set_property ("flags", _flags);
node->set_property ("locked", _locked); node->set_property ("locked", _locked);
node->set_property ("position-lock-style", _position_lock_style);
node->set_property ("timestamp", _timestamp); node->set_property ("timestamp", _timestamp);
if (_scene_change) { if (_scene_change) {
node->add_child_nocopy (_scene_change->get_state()); node->add_child_nocopy (_scene_change->get_state());
@ -690,67 +617,38 @@ Location::set_state (const XMLNode& node, int version)
cd_info[cd_name] = cd_value; cd_info[cd_name] = cd_value;
} }
node.get_property ("position-lock-style", _position_lock_style);
XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name); XMLNode* scene_child = find_named_node (node, SceneChange::xml_node_name);
if (scene_child) { if (scene_child) {
_scene_change = SceneChange::factory (*scene_child, version); _scene_change = SceneChange::factory (*scene_child, version);
} }
if (position_lock_style() == AudioTime) {
recompute_beat_from_samples (0);
} else{
/* music */
if (!node.get_property ("start-beat", _start_beat) ||
!node.get_property ("end-beat", _end_beat)) {
recompute_beat_from_samples (0);
}
}
changed (this); /* EMIT SIGNAL */ changed (this); /* EMIT SIGNAL */
Changed (); /* EMIT SIGNAL */ Changed (); /* EMIT SIGNAL */
assert (_start >= 0); assert (_start.positive() || _start.zero());
assert (_end >= 0); assert (_end.positive() || _end.zero());
return 0; return 0;
} }
void void
Location::set_position_lock_style (PositionLockStyle ps) Location::set_position_time_domain (TimeDomain domain)
{ {
if (_position_lock_style == ps) { if (_start.time_domain() == domain) {
return; return;
} }
_position_lock_style = ps; if (domain == Temporal::BeatTime) {
_start = timepos_t (_start.beats());
if (ps == MusicTime) { _end = timepos_t (_end.beats());
recompute_beat_from_samples (0); } else {
_start = timepos_t (_start.samples());
_end = timepos_t (_end.samples());
} }
position_lock_style_changed (this); /* EMIT SIGNAL */ position_time_domain_changed (this); /* EMIT SIGNAL */
PositionLockStyleChanged (); /* EMIT SIGNAL */ TimeDomainChanged (); /* EMIT SIGNAL */
}
void
Location::recompute_beat_from_samples (const uint32_t sub_num)
{
_start_beat = _session.tempo_map().exact_beat_at_sample (_start, sub_num);
_end_beat = _session.tempo_map().exact_beat_at_sample (_end, sub_num);
}
void
Location::recompute_samples_from_beat ()
{
if (_position_lock_style != MusicTime) {
return;
}
TempoMap& map (_session.tempo_map());
set (map.sample_at_beat (_start_beat), map.sample_at_beat (_end_beat), false);
} }
void void
@ -1184,11 +1082,10 @@ Locations::set_state (const XMLNode& node, int version)
Location* session_range_location = 0; Location* session_range_location = 0;
if (version < 3000) { if (version < 3000) {
session_range_location = new Location (_session, 0, 0, _("session"), Location::IsSessionRange, 0); session_range_location = new Location (_session, timepos_t (Temporal::AudioTime), timepos_t (Temporal::AudioTime), _("session"), Location::IsSessionRange);
new_locations.push_back (session_range_location); new_locations.push_back (session_range_location);
} }
XMLNodeConstIterator niter; XMLNodeConstIterator niter;
for (niter = nlist.begin(); niter != nlist.end(); ++niter) { for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
@ -1358,10 +1255,10 @@ Locations::mark_at (samplepos_t pos, samplecnt_t slop) const
for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) { for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {
if ((*i)->is_mark()) { if ((*i)->is_mark()) {
if (pos > (*i)->start()) { if (pos > (*i)->start_sample()) {
delta = pos - (*i)->start(); delta = pos - (*i)->start_sample();
} else { } else {
delta = (*i)->start() - pos; delta = (*i)->start_sample() - pos;
} }
if (slop == 0 && delta == 0) { if (slop == 0 && delta == 0) {
@ -1388,10 +1285,11 @@ Locations::first_mark_after (samplepos_t sample, bool include_special_ranges)
{ {
Glib::Threads::RWLock::ReaderLock lm (_lock); Glib::Threads::RWLock::ReaderLock lm (_lock);
for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) { for (LocationList::iterator i = locations.begin(); i != locations.end(); ++i) {
locs.push_back (make_pair ((*i)->start(), (*i))); locs.push_back (make_pair ((*i)->start_sample(), (*i)));
if (!(*i)->is_mark()) { if (!(*i)->is_mark()) {
locs.push_back (make_pair ((*i)->end(), (*i))); locs.push_back (make_pair ((*i)->end_sample(), (*i)));
} }
} }
} }
@ -1419,14 +1317,14 @@ Locations::first_mark_after (samplepos_t sample, bool include_special_ranges)
/** Look for the `marks' (either locations which are marks, or start/end points of range markers) either /** Look for the `marks' (either locations which are marks, or start/end points of range markers) either
* side of a sample. Note that if sample is exactly on a `mark', that mark will not be considered for returning * side of a sample. Note that if sample is exactly on a `mark', that mark will not be considered for returning
* as before/after. * as before/after.
* @param sample Frame to look for. * @param pos position to be used
* @param before Filled in with the position of the last `mark' before `sample' (or max_samplepos if none exists) * @param before Filled in with the position of the last `mark' before `pos' (or max_timepos if none exists)
* @param after Filled in with the position of the next `mark' after `sample' (or max_samplepos if none exists) * @param after Filled in with the position of the next `mark' after `pos' (or max_timepos if none exists)
*/ */
void void
Locations::marks_either_side (samplepos_t const sample, samplepos_t& before, samplepos_t& after) const Locations::marks_either_side (timepos_t const & pos, timepos_t& before, timepos_t& after) const
{ {
before = after = max_samplepos; before = after = std::numeric_limits<timepos_t>::max();
LocationList locs; LocationList locs;
@ -1437,7 +1335,7 @@ Locations::marks_either_side (samplepos_t const sample, samplepos_t& before, sam
/* Get a list of positions; don't store any that are exactly on our requested position */ /* Get a list of positions; don't store any that are exactly on our requested position */
std::list<samplepos_t> positions; std::list<timepos_t> positions;
for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) { for (LocationList::const_iterator i = locs.begin(); i != locs.end(); ++i) {
if (((*i)->is_auto_loop() || (*i)->is_auto_punch()) || (*i)->is_xrun()) { if (((*i)->is_auto_loop() || (*i)->is_auto_punch()) || (*i)->is_xrun()) {
@ -1446,14 +1344,14 @@ Locations::marks_either_side (samplepos_t const sample, samplepos_t& before, sam
if (!(*i)->is_hidden()) { if (!(*i)->is_hidden()) {
if ((*i)->is_mark ()) { if ((*i)->is_mark ()) {
if ((*i)->start() != sample) { if ((*i)->start() != pos) {
positions.push_back ((*i)->start ()); positions.push_back ((*i)->start ());
} }
} else { } else {
if ((*i)->start() != sample) { if ((*i)->start() != pos) {
positions.push_back ((*i)->start ()); positions.push_back ((*i)->start ());
} }
if ((*i)->end() != sample) { if ((*i)->end() != pos) {
positions.push_back ((*i)->end ()); positions.push_back ((*i)->end ());
} }
} }
@ -1466,8 +1364,9 @@ Locations::marks_either_side (samplepos_t const sample, samplepos_t& before, sam
positions.sort (); positions.sort ();
std::list<samplepos_t>::iterator i = positions.begin (); std::list<timepos_t>::iterator i = positions.begin ();
while (i != positions.end () && *i < sample) {
while (i != positions.end () && *i < pos) {
++i; ++i;
} }
@ -1567,7 +1466,7 @@ Locations::get_location_by_id(PBD::ID id)
} }
void void
Locations::find_all_between (samplepos_t start, samplepos_t end, LocationList& ll, Location::Flags flags) Locations::find_all_between (timepos_t const & start, timepos_t const & end, LocationList& ll, Location::Flags flags)
{ {
Glib::Threads::RWLock::ReaderLock lm (_lock); Glib::Threads::RWLock::ReaderLock lm (_lock);
for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) { for (LocationList::const_iterator i = locations.begin(); i != locations.end(); ++i) {

View file

@ -913,7 +913,7 @@ LuaAPI::Vamp::initialize ()
} }
int int
LuaAPI::Vamp::analyze (boost::shared_ptr<ARDOUR::Readable> r, uint32_t channel, luabridge::LuaRef cb) LuaAPI::Vamp::analyze (boost::shared_ptr<ARDOUR::AudioReadable> r, uint32_t channel, luabridge::LuaRef cb)
{ {
if (!_initialized) { if (!_initialized) {
if (!initialize ()) { if (!initialize ()) {
@ -926,7 +926,7 @@ LuaAPI::Vamp::analyze (boost::shared_ptr<ARDOUR::Readable> r, uint32_t channel,
float* data = new float[_bufsize]; float* data = new float[_bufsize];
float* bufs[1] = { data }; float* bufs[1] = { data };
samplecnt_t len = r->readable_length(); samplecnt_t len = r->readable_length_samples();
samplepos_t pos = 0; samplepos_t pos = 0;
int rv = 0; int rv = 0;
@ -1003,9 +1003,9 @@ LuaAPI::Rubberband::Rubberband (boost::shared_ptr<AudioRegion> r, bool percussiv
, _cb (0) , _cb (0)
{ {
_n_channels = r->n_channels (); _n_channels = r->n_channels ();
_read_len = r->length () / (double)r->stretch (); _read_len = r->length_samples () / (double)r->stretch ();
_read_start = r->ancestral_start () + samplecnt_t (r->start () / (double)r->stretch ()); _read_start = r->ancestral_start_sample () + samplecnt_t (r->start_sample () / (double)r->stretch ());
_read_offset = _read_start - r->start () + r->position (); _read_offset = _read_start - r->start_sample () + r->position_sample ();
} }
LuaAPI::Rubberband::~Rubberband () LuaAPI::Rubberband::~Rubberband ()
@ -1052,13 +1052,13 @@ LuaAPI::Rubberband::read (Sample* buf, samplepos_t pos, samplecnt_t cnt, int cha
static void null_deleter (LuaAPI::Rubberband*) {} static void null_deleter (LuaAPI::Rubberband*) {}
boost::shared_ptr<Readable> boost::shared_ptr<AudioReadable>
LuaAPI::Rubberband::readable () LuaAPI::Rubberband::readable ()
{ {
if (!_self) { if (!_self) {
_self = boost::shared_ptr<Rubberband> (this, &null_deleter); _self = boost::shared_ptr<Rubberband> (this, &null_deleter);
} }
return boost::dynamic_pointer_cast<Readable> (_self); return boost::dynamic_pointer_cast<AudioReadable> (_self);
} }
bool bool
@ -1205,7 +1205,7 @@ LuaAPI::Rubberband::finalize ()
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i); boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (*i);
assert (afs); assert (afs);
afs->done_with_peakfile_writes (); afs->done_with_peakfile_writes ();
afs->update_header (_region->position (), *now, xnow); afs->update_header (_region->position_sample (), *now, xnow);
afs->mark_immutable (); afs->mark_immutable ();
Analyser::queue_source_for_analysis (*i, false); Analyser::queue_source_for_analysis (*i, false);
sl.push_back (*i); sl.push_back (*i);
@ -1216,10 +1216,10 @@ LuaAPI::Rubberband::finalize ()
PropertyList plist; PropertyList plist;
plist.add (Properties::start, 0); plist.add (Properties::start, 0);
plist.add (Properties::length, _region->length ()); plist.add (Properties::length, _region->length_samples ());
plist.add (Properties::name, region_name); plist.add (Properties::name, region_name);
plist.add (Properties::whole_file, true); plist.add (Properties::whole_file, true);
plist.add (Properties::position, _region->position ()); plist.add (Properties::position, _region->position_sample ());
boost::shared_ptr<Region> r = RegionFactory::create (sl, plist); boost::shared_ptr<Region> r = RegionFactory::create (sl, plist);
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r); boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
@ -1231,9 +1231,9 @@ LuaAPI::Rubberband::finalize ()
ar->set_fade_out (_region->fade_out ()); ar->set_fade_out (_region->fade_out ());
*(ar->envelope ()) = *(_region->envelope ()); *(ar->envelope ()) = *(_region->envelope ());
ar->set_ancestral_data (_read_start, _read_len, _stretch_ratio, _pitch_ratio); ar->set_ancestral_data (timecnt_t (_read_start), timecnt_t (_read_len), _stretch_ratio, _pitch_ratio);
ar->set_master_sources (_region->master_sources ()); ar->set_master_sources (_region->master_sources ());
ar->set_length (ar->length () * _stretch_ratio, 0); // XXX ar->set_length (ar->nt_length () * _stretch_ratio); // XXX
if (_stretch_ratio != 1.0) { if (_stretch_ratio != 1.0) {
// TODO: apply mapping // TODO: apply mapping
ar->envelope ()->x_scale (_stretch_ratio); ar->envelope ()->x_scale (_stretch_ratio);

View file

@ -26,10 +26,10 @@
#include "pbd/openuri.h" #include "pbd/openuri.h"
#include "temporal/bbt_time.h" #include "temporal/bbt_time.h"
#include "temporal/range.h"
#include "evoral/Control.h" #include "evoral/Control.h"
#include "evoral/ControlList.h" #include "evoral/ControlList.h"
#include "evoral/Range.h"
#include "ardour/amp.h" #include "ardour/amp.h"
#include "ardour/async_midi_port.h" #include "ardour/async_midi_port.h"
@ -199,7 +199,6 @@ CLASSKEYS(Selectable*);
CLASSKEYS(std::list<Selectable*>); CLASSKEYS(std::list<Selectable*>);
CLASSKEYS(ARDOUR::AudioEngine); CLASSKEYS(ARDOUR::AudioEngine);
CLASSKEYS(ARDOUR::BeatsSamplesConverter);
CLASSKEYS(ARDOUR::BufferSet); CLASSKEYS(ARDOUR::BufferSet);
CLASSKEYS(ARDOUR::ChanCount); CLASSKEYS(ARDOUR::ChanCount);
CLASSKEYS(ARDOUR::ChanMapping); CLASSKEYS(ARDOUR::ChanMapping);
@ -254,7 +253,7 @@ CLASSKEYS(std::list<Evoral::ControlEvent*>);
CLASSKEYS(std::vector<ARDOUR::Plugin::PresetRecord>); CLASSKEYS(std::vector<ARDOUR::Plugin::PresetRecord>);
CLASSKEYS(std::vector<boost::shared_ptr<ARDOUR::Processor> >); CLASSKEYS(std::vector<boost::shared_ptr<ARDOUR::Processor> >);
CLASSKEYS(std::vector<boost::shared_ptr<ARDOUR::Source> >); CLASSKEYS(std::vector<boost::shared_ptr<ARDOUR::Source> >);
CLASSKEYS(std::vector<boost::shared_ptr<ARDOUR::Readable> >); CLASSKEYS(std::vector<boost::shared_ptr<ARDOUR::AudioReadable> >);
CLASSKEYS(std::vector<Evoral::Parameter>); CLASSKEYS(std::vector<Evoral::Parameter>);
CLASSKEYS(std::list<boost::shared_ptr<ARDOUR::PluginInfo> >); // PluginInfoList CLASSKEYS(std::list<boost::shared_ptr<ARDOUR::PluginInfo> >); // PluginInfoList
@ -281,7 +280,7 @@ CLASSKEYS(boost::shared_ptr<ARDOUR::MidiRegion>);
CLASSKEYS(boost::shared_ptr<ARDOUR::MidiSource>); CLASSKEYS(boost::shared_ptr<ARDOUR::MidiSource>);
CLASSKEYS(boost::shared_ptr<ARDOUR::PluginInfo>); CLASSKEYS(boost::shared_ptr<ARDOUR::PluginInfo>);
CLASSKEYS(boost::shared_ptr<ARDOUR::Processor>); CLASSKEYS(boost::shared_ptr<ARDOUR::Processor>);
CLASSKEYS(boost::shared_ptr<ARDOUR::Readable>); CLASSKEYS(boost::shared_ptr<ARDOUR::AudioReadable>);
CLASSKEYS(boost::shared_ptr<ARDOUR::Region>); CLASSKEYS(boost::shared_ptr<ARDOUR::Region>);
CLASSKEYS(boost::shared_ptr<ARDOUR::SessionPlaylists>); CLASSKEYS(boost::shared_ptr<ARDOUR::SessionPlaylists>);
CLASSKEYS(boost::shared_ptr<Evoral::ControlList>); CLASSKEYS(boost::shared_ptr<Evoral::ControlList>);
@ -582,7 +581,7 @@ LuaBindings::common (lua_State* L)
.addFunction ("set_interpolation", &Evoral::ControlList::set_interpolation) .addFunction ("set_interpolation", &Evoral::ControlList::set_interpolation)
.addFunction ("truncate_end", &Evoral::ControlList::truncate_end) .addFunction ("truncate_end", &Evoral::ControlList::truncate_end)
.addFunction ("truncate_start", &Evoral::ControlList::truncate_start) .addFunction ("truncate_start", &Evoral::ControlList::truncate_start)
.addFunction ("clear", (void (Evoral::ControlList::*)(double, double))&Evoral::ControlList::clear) .addFunction ("clear", (void (Evoral::ControlList::*)(timepos_t const &, timepos_t const &))&Evoral::ControlList::clear)
.addFunction ("clear_list", (void (Evoral::ControlList::*)())&Evoral::ControlList::clear) .addFunction ("clear_list", (void (Evoral::ControlList::*)())&Evoral::ControlList::clear)
.addFunction ("in_write_pass", &Evoral::ControlList::in_write_pass) .addFunction ("in_write_pass", &Evoral::ControlList::in_write_pass)
.addFunction ("events", &Evoral::ControlList::events) .addFunction ("events", &Evoral::ControlList::events)
@ -605,10 +604,11 @@ LuaBindings::common (lua_State* L)
.addData ("logarithmic", &Evoral::ParameterDescriptor::logarithmic) .addData ("logarithmic", &Evoral::ParameterDescriptor::logarithmic)
.endClass () .endClass ()
.beginClass <Evoral::Range<samplepos_t> > ("Range") .beginClass <Temporal::Range> ("Range")
.addConstructor <void (*) (samplepos_t, samplepos_t)> () .addConstructor <void (*) (timepos_t, timepos_t)> ()
.addData ("from", &Evoral::Range<samplepos_t>::from) .addFunction ("start", &Temporal::Range::start)
.addData ("to", &Evoral::Range<samplepos_t>::to) /* "end is a reserved Lua word */
.addFunction ("_end", &Temporal::Range::end)
.endClass () .endClass ()
.deriveWSPtrClass <Evoral::Sequence<Temporal::Beats>, Evoral::ControlSet> ("Sequence") .deriveWSPtrClass <Evoral::Sequence<Temporal::Beats>, Evoral::ControlSet> ("Sequence")
@ -771,20 +771,13 @@ LuaBindings::common (lua_State* L)
.beginClass <Progress> ("Progress") .beginClass <Progress> ("Progress")
.endClass () .endClass ()
.beginClass <MusicSample> ("MusicSample") .beginClass <TimelineRange> ("TimelineRange")
.addConstructor <void (*) (samplepos_t, int32_t)> () .addConstructor <void (*) (timepos_t, timepos_t, uint32_t)> ()
.addFunction ("set", &MusicSample::set) .addFunction ("length", &TimelineRange::length)
.addData ("sample", &MusicSample::sample) .addFunction ("equal", &TimelineRange::equal)
.addData ("division", &MusicSample::division) .addFunction ("start", &TimelineRange::start)
.endClass () .addFunction ("_end", &TimelineRange::end) // XXX "end" is a lua reserved word
.addData ("id", &TimelineRange::id)
.beginClass <AudioRange> ("AudioRange")
.addConstructor <void (*) (samplepos_t, samplepos_t, uint32_t)> ()
.addFunction ("length", &AudioRange::length)
.addFunction ("equal", &AudioRange::equal)
.addData ("start", &AudioRange::start)
.addData ("_end", &AudioRange::end) // XXX "end" is a lua reserved word
.addData ("id", &AudioRange::id)
.endClass () .endClass ()
.beginWSPtrClass <PluginInfo> ("PluginInfo") .beginWSPtrClass <PluginInfo> ("PluginInfo")
@ -1166,7 +1159,7 @@ LuaBindings::common (lua_State* L)
.addFunction ("lower_region", &Playlist::lower_region) .addFunction ("lower_region", &Playlist::lower_region)
.addFunction ("raise_region_to_top", &Playlist::raise_region_to_top) .addFunction ("raise_region_to_top", &Playlist::raise_region_to_top)
.addFunction ("lower_region_to_bottom", &Playlist::lower_region_to_bottom) .addFunction ("lower_region_to_bottom", &Playlist::lower_region_to_bottom)
.addFunction ("duplicate", (void (Playlist::*)(boost::shared_ptr<Region>, samplepos_t, samplecnt_t, float))&Playlist::duplicate) .addFunction ("duplicate", (void (Playlist::*)(boost::shared_ptr<Region>, timepos_t &, timecnt_t const &, float))&Playlist::duplicate)
.addFunction ("duplicate_until", &Playlist::duplicate_until) .addFunction ("duplicate_until", &Playlist::duplicate_until)
.addFunction ("duplicate_range", &Playlist::duplicate_range) .addFunction ("duplicate_range", &Playlist::duplicate_range)
.addFunction ("combine", &Playlist::combine) .addFunction ("combine", &Playlist::combine)
@ -1178,7 +1171,7 @@ LuaBindings::common (lua_State* L)
.addFunction ("split_region", &Playlist::split_region) .addFunction ("split_region", &Playlist::split_region)
.addFunction ("get_orig_track_id", &Playlist::get_orig_track_id) .addFunction ("get_orig_track_id", &Playlist::get_orig_track_id)
//.addFunction ("split", &Playlist::split) // XXX needs MusicSample //.addFunction ("split", &Playlist::split) // XXX needs MusicSample
.addFunction ("cut", (boost::shared_ptr<Playlist> (Playlist::*)(std::list<AudioRange>&, bool))&Playlist::cut) .addFunction ("cut", (boost::shared_ptr<Playlist> (Playlist::*)(std::list<TimelineRange>&, bool))&Playlist::cut)
#if 0 #if 0
.addFunction ("copy", &Playlist::copy) .addFunction ("copy", &Playlist::copy)
.addFunction ("paste", &Playlist::paste) .addFunction ("paste", &Playlist::paste)
@ -1239,28 +1232,27 @@ LuaBindings::common (lua_State* L)
.addFunction ("write_immediate_event", &MidiTrack::write_immediate_event) .addFunction ("write_immediate_event", &MidiTrack::write_immediate_event)
.endClass () .endClass ()
.beginWSPtrClass <Readable> ("Readable") .beginWSPtrClass <AudioReadable> ("Readable")
.addFunction ("read", &Readable::read) .addFunction ("read", &AudioReadable::read)
.addFunction ("readable_length", &Readable::readable_length) .addFunction ("readable_length", &AudioReadable::readable_length_samples)
.addFunction ("n_channels", &Readable::n_channels) .addFunction ("n_channels", &AudioReadable::n_channels)
.addStaticFunction ("load", &Readable::load) .addStaticFunction ("load", &AudioReadable::load)
.endClass () .endClass ()
.deriveWSPtrClass <AudioRom, Readable> ("AudioRom") .deriveWSPtrClass <AudioRom, AudioReadable> ("AudioRom")
.addStaticFunction ("new_rom", &AudioRom::new_rom) .addStaticFunction ("new_rom", &AudioRom::new_rom)
.endClass () .endClass ()
.deriveWSPtrClass <Region, SessionObject> ("Region") .deriveWSPtrClass <Region, SessionObject> ("Region")
.addCast<Readable> ("to_readable")
.addCast<MidiRegion> ("to_midiregion") .addCast<MidiRegion> ("to_midiregion")
.addCast<AudioRegion> ("to_audioregion") .addCast<AudioRegion> ("to_audioregion")
.addFunction ("playlist", &Region::playlist) .addFunction ("playlist", &Region::playlist)
.addFunction ("set_name", &Region::set_name) .addFunction ("set_name", &Region::set_name)
/* properties */ /* properties */
.addFunction ("position", &Region::position) .addFunction ("position", &Region::nt_position)
.addFunction ("start", &Region::start) .addFunction ("start", &Region::nt_start)
.addFunction ("length", &Region::length) .addFunction ("length", &Region::nt_length)
.addFunction ("layer", &Region::layer) .addFunction ("layer", &Region::layer)
.addFunction ("data_type", &Region::data_type) .addFunction ("data_type", &Region::data_type)
.addFunction ("stretch", &Region::stretch) .addFunction ("stretch", &Region::stretch)
@ -1280,7 +1272,7 @@ LuaBindings::common (lua_State* L)
.addFunction ("sync_marked", &Region::sync_marked) .addFunction ("sync_marked", &Region::sync_marked)
.addFunction ("external", &Region::external) .addFunction ("external", &Region::external)
.addFunction ("import", &Region::import) .addFunction ("import", &Region::import)
.addFunction ("covers", &Region::covers) .addFunction ("covers", (bool (Region::*)(timepos_t const &) const) &Region::covers)
.addFunction ("at_natural_position", &Region::at_natural_position) .addFunction ("at_natural_position", &Region::at_natural_position)
.addFunction ("is_compound", &Region::is_compound) .addFunction ("is_compound", &Region::is_compound)
.addFunction ("captured_xruns", &Region::captured_xruns) .addFunction ("captured_xruns", &Region::captured_xruns)
@ -1298,7 +1290,6 @@ LuaBindings::common (lua_State* L)
.addFunction ("move_start", &Region::move_start) .addFunction ("move_start", &Region::move_start)
.addFunction ("master_sources", &Region::master_sources) .addFunction ("master_sources", &Region::master_sources)
.addFunction ("master_source_names", &Region::master_source_names) .addFunction ("master_source_names", &Region::master_source_names)
.addFunction ("n_channels", &Region::n_channels)
.addFunction ("trim_front", &Region::trim_front) .addFunction ("trim_front", &Region::trim_front)
.addFunction ("trim_end", &Region::trim_end) .addFunction ("trim_end", &Region::trim_end)
.addFunction ("trim_to", &Region::trim_to) .addFunction ("trim_to", &Region::trim_to)
@ -1310,7 +1301,6 @@ LuaBindings::common (lua_State* L)
.addFunction ("lower_to_bottom", &Region::lower_to_bottom) .addFunction ("lower_to_bottom", &Region::lower_to_bottom)
.addFunction ("set_sync_position", &Region::set_sync_position) .addFunction ("set_sync_position", &Region::set_sync_position)
.addFunction ("clear_sync_position", &Region::clear_sync_position) .addFunction ("clear_sync_position", &Region::clear_sync_position)
.addFunction ("quarter_note", &Region::quarter_note)
.addFunction ("set_hidden", &Region::set_hidden) .addFunction ("set_hidden", &Region::set_hidden)
.addFunction ("set_muted", &Region::set_muted) .addFunction ("set_muted", &Region::set_muted)
.addFunction ("set_opaque", &Region::set_opaque) .addFunction ("set_opaque", &Region::set_opaque)
@ -1325,11 +1315,11 @@ LuaBindings::common (lua_State* L)
.addFunction ("do_export", &MidiRegion::do_export) .addFunction ("do_export", &MidiRegion::do_export)
.addFunction ("midi_source", &MidiRegion::midi_source) .addFunction ("midi_source", &MidiRegion::midi_source)
.addFunction ("model", (boost::shared_ptr<MidiModel> (MidiRegion::*)())&MidiRegion::model) .addFunction ("model", (boost::shared_ptr<MidiModel> (MidiRegion::*)())&MidiRegion::model)
.addFunction ("start_beats", &MidiRegion::start_beats)
.addFunction ("length_beats", &MidiRegion::length_beats)
.endClass () .endClass ()
.deriveWSPtrClass <AudioRegion, Region> ("AudioRegion") .deriveWSPtrClass <AudioRegion, Region> ("AudioRegion")
.addCast<AudioReadable> ("to_readable")
.addFunction ("n_channels", &AudioRegion::n_channels)
.addFunction ("audio_source", &AudioRegion::audio_source) .addFunction ("audio_source", &AudioRegion::audio_source)
.addFunction ("set_scale_amplitude", &AudioRegion::set_scale_amplitude) .addFunction ("set_scale_amplitude", &AudioRegion::set_scale_amplitude)
.addFunction ("scale_amplitude", &AudioRegion::scale_amplitude) .addFunction ("scale_amplitude", &AudioRegion::scale_amplitude)
@ -1383,8 +1373,8 @@ LuaBindings::common (lua_State* L)
.endClass () .endClass ()
.deriveWSPtrClass <AudioSource, Source> ("AudioSource") .deriveWSPtrClass <AudioSource, Source> ("AudioSource")
.addCast<Readable> ("to_readable") .addCast<AudioReadable> ("to_readable")
.addFunction ("readable_length", &AudioSource::readable_length) .addFunction ("readable_length", &AudioSource::readable_length_samples)
.addFunction ("n_channels", &AudioSource::n_channels) .addFunction ("n_channels", &AudioSource::n_channels)
.addFunction ("empty", &Source::empty) .addFunction ("empty", &Source::empty)
.addFunction ("length", &Source::length) .addFunction ("length", &Source::length)
@ -1745,7 +1735,7 @@ LuaBindings::common (lua_State* L)
.endClass () .endClass ()
.deriveWSPtrClass <AudioSource, Source> ("AudioSource") .deriveWSPtrClass <AudioSource, Source> ("AudioSource")
.addFunction ("readable_length", &AudioSource::readable_length) .addFunction ("readable_length", &AudioSource::readable_length_samples)
.addFunction ("n_channels", &AudioSource::n_channels) .addFunction ("n_channels", &AudioSource::n_channels)
.endClass () .endClass ()
@ -1795,8 +1785,8 @@ LuaBindings::common (lua_State* L)
.beginStdVector <boost::shared_ptr<Source> > ("SourceList") .beginStdVector <boost::shared_ptr<Source> > ("SourceList")
.endClass () .endClass ()
// typedef std::vector<boost::shared_ptr<Readable> > // typedef std::vector<boost::shared_ptr<AudioReadable> >
.beginStdVector <boost::shared_ptr<Readable> > ("ReadableList") .beginStdVector <boost::shared_ptr<AudioReadable> > ("ReadableList")
.endClass () .endClass ()
// from SessionPlaylists: std::vector<boost::shared_ptr<Playlist > > // from SessionPlaylists: std::vector<boost::shared_ptr<Playlist > >
@ -1844,17 +1834,12 @@ LuaBindings::common (lua_State* L)
.beginConstStdList <boost::shared_ptr<Port> > ("PortList") .beginConstStdList <boost::shared_ptr<Port> > ("PortList")
.endClass () .endClass ()
// used by Playlist::cut/copy
.beginConstStdList <AudioRange> ("AudioRangeList")
.endClass ()
.beginConstStdCPtrList <Location> ("LocationList") .beginConstStdCPtrList <Location> ("LocationList")
.endClass () .endClass ()
.beginConstStdVector <Evoral::Parameter> ("ParameterList") .beginConstStdVector <Evoral::Parameter> ("ParameterList")
.endClass () .endClass ()
// std::list<boost::shared_ptr<AutomationControl> > ControlList
.beginStdList <boost::shared_ptr<AutomationControl> > ("ControlList") .beginStdList <boost::shared_ptr<AutomationControl> > ("ControlList")
.endClass () .endClass ()
@ -1897,12 +1882,6 @@ LuaBindings::common (lua_State* L)
.addFunction ("samples_per_grid", &Meter::samples_per_grid) .addFunction ("samples_per_grid", &Meter::samples_per_grid)
.endClass () .endClass ()
.beginClass <BeatsSamplesConverter> ("BeatsSamplesConverter")
.addConstructor <void (*) (const TempoMap&, samplepos_t)> ()
.addFunction ("to", &BeatsSamplesConverter::to)
.addFunction ("from", &BeatsSamplesConverter::from)
.endClass ()
.beginClass <TempoMap> ("TempoMap") .beginClass <TempoMap> ("TempoMap")
.addFunction ("add_tempo", &TempoMap::add_tempo) .addFunction ("add_tempo", &TempoMap::add_tempo)
.addFunction ("add_meter", &TempoMap::add_meter) .addFunction ("add_meter", &TempoMap::add_meter)
@ -2666,7 +2645,7 @@ LuaBindings::common (lua_State* L)
.addFunction ("set_strech_and_pitch", &ARDOUR::LuaAPI::Rubberband::set_strech_and_pitch) .addFunction ("set_strech_and_pitch", &ARDOUR::LuaAPI::Rubberband::set_strech_and_pitch)
.addFunction ("set_mapping", &ARDOUR::LuaAPI::Rubberband::set_mapping) .addFunction ("set_mapping", &ARDOUR::LuaAPI::Rubberband::set_mapping)
.addFunction ("process", &ARDOUR::LuaAPI::Rubberband::process) .addFunction ("process", &ARDOUR::LuaAPI::Rubberband::process)
.addFunction ("readable_length", &ARDOUR::LuaAPI::Rubberband::readable_length) .addFunction ("readable_length", &ARDOUR::LuaAPI::Rubberband::readable_length_samples)
.addFunction ("n_channels", &ARDOUR::LuaAPI::Rubberband::n_channels) .addFunction ("n_channels", &ARDOUR::LuaAPI::Rubberband::n_channels)
.addFunction ("readable", &ARDOUR::LuaAPI::Rubberband::readable) .addFunction ("readable", &ARDOUR::LuaAPI::Rubberband::readable)
.endClass () .endClass ()

View file

@ -2934,9 +2934,9 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
assert (start + samples - _current_latency >= 0); assert (start + samples - _current_latency >= 0);
if (c->guard) { if (c->guard) {
c->guard = false; c->guard = false;
c->ac->list()->add (when, v, true, true); c->ac->list()->add (timepos_t (when), v, true, true);
} else { } else {
c->ac->set_double (v, when, true); c->ac->set_double (v, timepos_t (when), true);
} }
} }
} }
@ -2993,7 +2993,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
AutomationCtrlPtr c = get_automation_control (p); AutomationCtrlPtr c = get_automation_control (p);
DEBUG_TRACE(DEBUG::LV2Automate, string_compose ("Start Touch p: %1\n", p)); DEBUG_TRACE(DEBUG::LV2Automate, string_compose ("Start Touch p: %1\n", p));
if (c) { if (c) {
c->ac->start_touch (std::max ((samplepos_t)0, start - _current_latency)); c->ac->start_touch (timepos_t (std::max ((samplepos_t)0, start - _current_latency)));
c->guard = true; c->guard = true;
} }
} }
@ -3008,7 +3008,7 @@ LV2Plugin::connect_and_run(BufferSet& bufs,
AutomationCtrlPtr c = get_automation_control (p); AutomationCtrlPtr c = get_automation_control (p);
DEBUG_TRACE(DEBUG::LV2Automate, string_compose ("End Touch p: %1\n", p)); DEBUG_TRACE(DEBUG::LV2Automate, string_compose ("End Touch p: %1\n", p));
if (c) { if (c) {
c->ac->stop_touch (std::max ((samplepos_t)0, start - _current_latency)); c->ac->stop_touch (timepos_t (std::max ((samplepos_t)0, start - _current_latency)));
} }
} }
} }

View file

@ -1472,16 +1472,16 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
TimeType sb = (*i)->time(); TimeType sb = (*i)->time();
TimeType eb = (*i)->end_time(); TimeType eb = (*i)->end_time();
OverlapType overlap = OverlapNone; Temporal::OverlapType overlap = Temporal::OverlapNone;
if ((sb > sa) && (eb <= ea)) { if ((sb > sa) && (eb <= ea)) {
overlap = OverlapInternal; overlap = Temporal::OverlapInternal;
} else if ((eb > sa) && (eb <= ea)) { } else if ((eb > sa) && (eb <= ea)) {
overlap = OverlapStart; overlap = Temporal::OverlapStart;
} else if ((sb > sa) && (sb < ea)) { } else if ((sb > sa) && (sb < ea)) {
overlap = OverlapEnd; overlap = Temporal::OverlapEnd;
} else if ((sa >= sb) && (sa <= eb) && (ea <= eb)) { } else if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
overlap = OverlapExternal; overlap = Temporal::OverlapExternal;
} else { } else {
/* no overlap */ /* no overlap */
continue; continue;
@ -1497,7 +1497,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
} }
switch (overlap) { switch (overlap) {
case OverlapStart: case Temporal::OverlapStart:
cerr << "OverlapStart\n"; cerr << "OverlapStart\n";
/* existing note covers start of new note */ /* existing note covers start of new note */
switch (insert_merge_policy()) { switch (insert_merge_policy()) {
@ -1530,7 +1530,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
} }
break; break;
case OverlapEnd: case Temporal::OverlapEnd:
cerr << "OverlapEnd\n"; cerr << "OverlapEnd\n";
/* existing note covers end of new note */ /* existing note covers end of new note */
switch (insert_merge_policy()) { switch (insert_merge_policy()) {
@ -1566,7 +1566,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
} }
break; break;
case OverlapExternal: case Temporal::OverlapExternal:
cerr << "OverlapExt\n"; cerr << "OverlapExt\n";
/* existing note overlaps all the new note */ /* existing note overlaps all the new note */
switch (insert_merge_policy()) { switch (insert_merge_policy()) {
@ -1585,7 +1585,7 @@ MidiModel::resolve_overlaps_unlocked (const NotePtr note, void* arg)
} }
break; break;
case OverlapInternal: case Temporal::OverlapInternal:
cerr << "OverlapInt\n"; cerr << "OverlapInt\n";
/* new note fully overlaps an existing note */ /* new note fully overlaps an existing note */
switch (insert_merge_policy()) { switch (insert_merge_policy()) {
@ -1784,7 +1784,7 @@ MidiModel::insert_silence_at_start (TimeType t)
for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) { for (Controls::iterator i = controls().begin(); i != controls().end(); ++i) {
boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second); boost::shared_ptr<AutomationControl> ac = boost::dynamic_pointer_cast<AutomationControl> (i->second);
XMLNode& before = ac->alist()->get_state (); XMLNode& before = ac->alist()->get_state ();
i->second->list()->shift (0, t.to_double()); i->second->list()->shift (timepos_t::zero (i->second->list()->time_domain()), timecnt_t (t));
XMLNode& after = ac->alist()->get_state (); XMLNode& after = ac->alist()->get_state ();
s->session().add_command (new MementoCommand<AutomationList> (new MidiAutomationListBinder (s, i->first), &before, &after)); s->session().add_command (new MementoCommand<AutomationList> (new MidiAutomationListBinder (s, i->first), &before, &after));
} }
@ -1801,7 +1801,7 @@ MidiModel::insert_silence_at_start (TimeType t)
apply_command_as_subcommand (s->session(), c); apply_command_as_subcommand (s->session(), c);
} }
ContentsShifted (t.to_double()); ContentsShifted (timecnt_t (t));
} }
void void

View file

@ -78,8 +78,8 @@ MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, string
} }
MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other, MidiPlaylist::MidiPlaylist (boost::shared_ptr<const MidiPlaylist> other,
samplepos_t start, timepos_t const & start,
samplecnt_t dur, timepos_t const & dur,
string name, string name,
bool hidden) bool hidden)
: Playlist (other, start, dur, name, hidden) : Playlist (other, start, dur, name, hidden)
@ -149,9 +149,9 @@ MidiPlaylist::dump () const
for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) { for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
r = *i; r = *i;
cerr << " " << r->name() << " @ " << r << " [" cerr << " " << r->name() << " @ " << r << " ["
<< r->start() << "+" << r->length() << r->nt_start() << "+" << r->nt_length()
<< "] at " << "] at "
<< r->position() << r->nt_position()
<< " on layer " << " on layer "
<< r->layer () << r->layer ()
<< endl; << endl;
@ -196,14 +196,14 @@ MidiPlaylist::destroy_region (boost::shared_ptr<Region> region)
return changed; return changed;
} }
void void
MidiPlaylist::_split_region (boost::shared_ptr<Region> region, const MusicSample& playlist_position, ThawList& thawlist) MidiPlaylist::_split_region (boost::shared_ptr<Region> region, timepos_t const & playlist_position, Thawlist& thawlist)
{ {
if (!region->covers (playlist_position.sample)) { if (!region->covers (playlist_position)) {
return; return;
} }
if (region->position() == playlist_position.sample || if (region->nt_position() == playlist_position ||
region->last_sample() == playlist_position.sample) { region->nt_last() == playlist_position) {
return; return;
} }
@ -218,18 +218,16 @@ MidiPlaylist::_split_region (boost::shared_ptr<Region> region, const MusicSample
string before_name; string before_name;
string after_name; string after_name;
const double before_qn = _session.tempo_map().exact_qn_at_sample (playlist_position.sample, playlist_position.division) - region->quarter_note();
const double after_qn = mr->length_beats() - before_qn; const timecnt_t before = region->nt_position().distance (playlist_position);
MusicSample before (playlist_position.sample - region->position(), playlist_position.division); const timecnt_t after = region->nt_length() - before;
MusicSample after (region->length() - before.sample, playlist_position.division);
RegionFactory::region_name (before_name, region->name(), false); RegionFactory::region_name (before_name, region->name(), false);
{ {
PropertyList plist; PropertyList plist;
plist.add (Properties::length, before.sample); plist.add (Properties::length, before);
plist.add (Properties::length_beats, before_qn);
plist.add (Properties::name, before_name); plist.add (Properties::name, before_name);
plist.add (Properties::left_of_split, true); plist.add (Properties::left_of_split, true);
plist.add (Properties::layering_index, region->layering_index ()); plist.add (Properties::layering_index, region->layering_index ());
@ -239,7 +237,7 @@ MidiPlaylist::_split_region (boost::shared_ptr<Region> region, const MusicSample
since it supplies that offset to the Region constructor, which since it supplies that offset to the Region constructor, which
is necessary to get audio region gain envelopes right. is necessary to get audio region gain envelopes right.
*/ */
left = RegionFactory::create (region, MusicSample (0, 0), plist, true, &thawlist); left = RegionFactory::create (region, plist, true, &thawlist);
} }
RegionFactory::region_name (after_name, region->name(), false); RegionFactory::region_name (after_name, region->name(), false);
@ -247,8 +245,7 @@ MidiPlaylist::_split_region (boost::shared_ptr<Region> region, const MusicSample
{ {
PropertyList plist; PropertyList plist;
plist.add (Properties::length, after.sample); plist.add (Properties::length, after);
plist.add (Properties::length_beats, after_qn);
plist.add (Properties::name, after_name); plist.add (Properties::name, after_name);
plist.add (Properties::right_of_split, true); plist.add (Properties::right_of_split, true);
plist.add (Properties::layering_index, region->layering_index ()); plist.add (Properties::layering_index, region->layering_index ());
@ -258,8 +255,8 @@ MidiPlaylist::_split_region (boost::shared_ptr<Region> region, const MusicSample
right = RegionFactory::create (region, before, plist, true, &thawlist); right = RegionFactory::create (region, before, plist, true, &thawlist);
} }
add_region_internal (left, region->position(), thawlist, 0, region->quarter_note(), true); add_region_internal (left, region->nt_position(), thawlist);
add_region_internal (right, region->position() + before.sample, thawlist, before.division, region->quarter_note() + before_qn, true); add_region_internal (right, region->nt_position() + before, thawlist);
remove_region_internal (region, thawlist); remove_region_internal (region, thawlist);
} }

View file

@ -1,204 +0,0 @@
/*
* Copyright (C) 2011-2015 David Robillard <d@drobilla.net>
* Copyright (C) 2011-2017 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef WAF_BUILD
#include "libardour-config.h"
#endif
#include "pbd/error.h"
#include "ardour/midi_playlist.h"
#include "ardour/midi_playlist_source.h"
#include "pbd/i18n.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
namespace ARDOUR {
class MidiStateTracker;
class Session;
template <typename T> class MidiRingBuffer;
}
namespace Evoral {
template <typename T> class EventSink;
template <typename Time> class Event;
}
/*******************************************************************************
As of May 2011, it appears too complex to support compound regions for MIDI
because of the need to be able to edit the data represented by the region. It
seems that it would be a better idea to render the consituent regions into a
new MIDI file and create a new region based on that, an operation we have been
calling "consolidate"
This code has been in place as a stub in case anyone gets any brilliant ideas
on other ways to approach this issue.
********************************************************************************/
MidiPlaylistSource::MidiPlaylistSource (Session& s, const ID& orig, const std::string& name, boost::shared_ptr<MidiPlaylist> p,
uint32_t /*chn*/, sampleoffset_t begin, samplecnt_t len, Source::Flag flags)
: Source (s, DataType::MIDI, name)
, MidiSource (s, name, flags)
, PlaylistSource (s, orig, name, p, DataType::MIDI, begin, len, flags)
{
}
MidiPlaylistSource::MidiPlaylistSource (Session& s, const XMLNode& node)
: Source (s, node)
, MidiSource (s, node)
, PlaylistSource (s, node)
{
/* PlaylistSources are never writable, renameable or removable */
_flags = Flag (_flags & ~(Writable|CanRename|Removable|RemovableIfEmpty|RemoveAtDestroy));
/* ancestors have already called ::set_state() in their XML-based
constructors.
*/
if (set_state (node, Stateful::loading_state_version, false)) {
throw failed_constructor ();
}
}
MidiPlaylistSource::~MidiPlaylistSource ()
{
}
XMLNode&
MidiPlaylistSource::get_state ()
{
XMLNode& node (MidiSource::get_state ());
/* merge PlaylistSource state */
PlaylistSource::add_state (node);
return node;
}
int
MidiPlaylistSource::set_state (const XMLNode& node, int version)
{
return set_state (node, version, true);
}
int
MidiPlaylistSource::set_state (const XMLNode& node, int version, bool with_descendants)
{
if (with_descendants) {
if (Source::set_state (node, version) ||
MidiSource::set_state (node, version) ||
PlaylistSource::set_state (node, version)) {
return -1;
}
}
return 0;
}
samplecnt_t
MidiPlaylistSource::length (samplepos_t) const
{
pair<samplepos_t,samplepos_t> extent = _playlist->get_extent();
return extent.second - extent.first;
}
samplecnt_t
MidiPlaylistSource::read_unlocked (const Lock& lock,
Evoral::EventSink<samplepos_t>& dst,
samplepos_t /*position*/,
samplepos_t start,
samplecnt_t cnt,
Evoral::Range<samplepos_t>* loop_range,
MidiStateTracker*,
MidiChannelFilter*) const
{
boost::shared_ptr<MidiPlaylist> mp = boost::dynamic_pointer_cast<MidiPlaylist> (_playlist);
if (!mp) {
return 0;
}
/* XXX paul says on Oct 26 2019:
rgareus: so to clarify now that i have better perspective: the API i want to get rid of is MidiPlaylist::read() ; everything that used it (i.e. the DiskReader) should use MidiPlaylist::rendered()->read()
rgareus: but a "read" operation is also a "write" operation: you have to put the data somewhere
rgareus: the only other user of MidiPlaylist::read() was MidiPlaylistSource (unsurprisingly), which as I noted is not even (really) used
rgareus: ::rendered() returns a ptr-to-RT_MidiBuffer, which has a read method which expects to write into a MidiBuffer, using push_back()
rgareus: but MidiPlaylistSource::read() is given an EventSink<samplepos_t> as the destination, and this does not (currently) have ::push_back(), only ::write() (which is willing to deal with inserts rather than appends)
rgareus: so, this is the API "mess" I'm trying to clean up. simple solution: since we don't use MidiPlaylistSource just comment out the line and forget about it for now, then remove MidiPlaylist::read() and move on
This represents that decision, for now.
*/
return cnt; // mp->read (dst, start, cnt, loop_range);
}
samplecnt_t
MidiPlaylistSource::write_unlocked (const Lock&,
MidiRingBuffer<samplepos_t>&,
samplepos_t,
samplecnt_t)
{
fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::write_unlocked() called - should be impossible") << endmsg;
abort(); /*NOTREACHED*/
return 0;
}
void
MidiPlaylistSource::append_event_beats(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<Temporal::Beats>& /*ev*/)
{
fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_beats() called - should be impossible") << endmsg;
abort(); /*NOTREACHED*/
}
void
MidiPlaylistSource::append_event_samples(const Glib::Threads::Mutex::Lock& /*lock*/, const Evoral::Event<samplepos_t>& /* ev */, samplepos_t /*source_start*/)
{
fatal << string_compose (_("programming error: %1"), "MidiPlaylistSource::append_event_samples() called - should be impossible") << endmsg;
abort(); /*NOTREACHED*/
}
void
MidiPlaylistSource::load_model (const Glib::Threads::Mutex::Lock&, bool)
{
/* nothing to do */
}
void
MidiPlaylistSource::destroy_model (const Glib::Threads::Mutex::Lock&)
{
/* nothing to do */
}
void
MidiPlaylistSource::flush_midi (const Lock& lock)
{
}
bool
MidiPlaylistSource::empty () const
{
return !_playlist || _playlist->empty();
}

View file

@ -60,18 +60,9 @@ using namespace std;
using namespace ARDOUR; using namespace ARDOUR;
using namespace PBD; using namespace PBD;
namespace ARDOUR {
namespace Properties {
PBD::PropertyDescriptor<double> start_beats;
PBD::PropertyDescriptor<double> length_beats;
}
}
/* Basic MidiRegion constructor (many channels) */ /* Basic MidiRegion constructor (many channels) */
MidiRegion::MidiRegion (const SourceList& srcs) MidiRegion::MidiRegion (const SourceList& srcs)
: Region (srcs) : Region (srcs)
, _start_beats (Properties::start_beats, 0.0)
, _length_beats (Properties::length_beats, midi_source(0)->length_beats().to_double())
, _ignore_shift (false) , _ignore_shift (false)
{ {
midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this)); midi_source(0)->ModelChanged.connect_same_thread (_source_connection, boost::bind (&MidiRegion::model_changed, this));
@ -82,8 +73,6 @@ MidiRegion::MidiRegion (const SourceList& srcs)
MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other) MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other)
: Region (other) : Region (other)
, _start_beats (Properties::start_beats, other->_start_beats)
, _length_beats (Properties::length_beats, other->_length_beats)
, _ignore_shift (false) , _ignore_shift (false)
{ {
assert(_name.val().find("/") == string::npos); assert(_name.val().find("/") == string::npos);
@ -94,8 +83,6 @@ MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other)
/** Create a new MidiRegion that is part of an existing one */ /** Create a new MidiRegion that is part of an existing one */
MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, timecnt_t const & offset) MidiRegion::MidiRegion (boost::shared_ptr<const MidiRegion> other, timecnt_t const & offset)
: Region (other, offset) : Region (other, offset)
, _start_beats (Properties::start_beats, other->_start_beats)
, _length_beats (Properties::length_beats, other->_length_beats)
, _ignore_shift (false) , _ignore_shift (false)
{ {
@ -118,17 +105,13 @@ MidiRegion::do_export (string path) const
/* caller must check for pre-existing file */ /* caller must check for pre-existing file */
assert (!path.empty()); assert (!path.empty());
assert (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)); assert (!Glib::file_test (path, Glib::FILE_TEST_EXISTS));
newsrc = boost::dynamic_pointer_cast<MidiSource>(SourceFactory::createWritable(DataType::MIDI, _session, path, _session.sample_rate())); newsrc = boost::dynamic_pointer_cast<MidiSource>(SourceFactory::createWritable(DataType::MIDI, _session, path, false, _session.sample_rate()));
BeatsSamplesConverter bfc (_session.tempo_map(), _position);
Temporal::Beats const bbegin = bfc.from (_start);
Temporal::Beats const bend = bfc.from (_start + _length);
{ {
/* Lock our source since we'll be reading from it. write_to() will /* Lock our source since we'll be reading from it. write_to() will
take a lock on newsrc. */ take a lock on newsrc. */
Source::Lock lm (midi_source(0)->mutex()); Source::Lock lm (midi_source(0)->mutex());
if (midi_source(0)->export_write_to (lm, newsrc, bbegin, bend)) { if (midi_source(0)->export_write_to (lm, newsrc, _start.val().beats(), _start.val().beats() + _length.val().beats())) {
return false; return false;
} }
} }
@ -155,9 +138,8 @@ MidiRegion::clone (string path) const
boost::shared_ptr<MidiRegion> boost::shared_ptr<MidiRegion>
MidiRegion::clone (boost::shared_ptr<MidiSource> newsrc, ThawList* tl) const MidiRegion::clone (boost::shared_ptr<MidiSource> newsrc, ThawList* tl) const
{ {
BeatsSamplesConverter bfc (_session.tempo_map(), _position); Temporal::Beats const bbegin = _start.val().beats ();
Temporal::Beats const bbegin = bfc.from (_start); Temporal::Beats const bend = _start.val().beats() + _length.val().beats();
Temporal::Beats const bend = bfc.from (_start + _length);
{ {
boost::shared_ptr<MidiSource> ms = midi_source(0); boost::shared_ptr<MidiSource> ms = midi_source(0);
@ -181,215 +163,80 @@ MidiRegion::clone (boost::shared_ptr<MidiSource> newsrc, ThawList* tl) const
plist.add (Properties::name, PBD::basename_nosuffix (newsrc->name())); plist.add (Properties::name, PBD::basename_nosuffix (newsrc->name()));
plist.add (Properties::whole_file, true); plist.add (Properties::whole_file, true);
plist.add (Properties::start, _start); plist.add (Properties::start, _start);
plist.add (Properties::start_beats, _start_beats);
plist.add (Properties::length, _length); plist.add (Properties::length, _length);
plist.add (Properties::position, _position); plist.add (Properties::position, _position);
plist.add (Properties::beat, _beat);
plist.add (Properties::length_beats, _length_beats);
plist.add (Properties::layer, 0); plist.add (Properties::layer, 0);
boost::shared_ptr<MidiRegion> ret (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (newsrc, plist, true, tl))); boost::shared_ptr<MidiRegion> ret (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (newsrc, plist, true, tl)));
ret->set_quarter_note (quarter_note());
return ret; return ret;
} }
void timecnt_t
MidiRegion::post_set (const PropertyChange& pc)
{
Region::post_set (pc);
if (pc.contains (Properties::length) && !pc.contains (Properties::length_beats)) {
/* we're called by Stateful::set_values() which sends a change
only if the value is different from _current.
session load means we can clobber length_beats here in error (not all properties differ from current),
so disallow (this has been set from XML state anyway).
*/
if (!_session.loading()) {
update_length_beats (0);
}
}
if (pc.contains (Properties::start) && !pc.contains (Properties::start_beats)) {
set_start_beats_from_start_samples ();
}
}
void
MidiRegion::set_start_beats_from_start_samples ()
{
if (position_lock_style() == AudioTime) {
_start_beats = quarter_note() - _session.tempo_map().quarter_note_at_sample (_position - _start);
}
}
void
MidiRegion::set_length_internal (samplecnt_t len, const int32_t sub_num)
{
Region::set_length_internal (len, sub_num);
update_length_beats (sub_num);
}
void
MidiRegion::update_after_tempo_map_change (bool /* send */)
{
boost::shared_ptr<Playlist> pl (playlist());
if (!pl) {
return;
}
const samplepos_t old_pos = _position;
const samplepos_t old_length = _length;
const samplepos_t old_start = _start;
PropertyChange s_and_l;
if (position_lock_style() == AudioTime) {
recompute_position_from_lock_style (0);
/*
set _start to new position in tempo map.
The user probably expects the region contents to maintain audio position as the
tempo changes, but AFAICT this requires modifying the src file to use
SMPTE timestamps with the current disk read model (?).
We could arguably use _start to set _start_beats here,
resulting in viewport-like behaviour (the contents maintain
their musical position while the region is stationary).
For now, the musical position at the region start is retained, but subsequent events
will maintain their beat distance according to the map.
*/
_start = _session.tempo_map().samples_between_quarter_notes (quarter_note() - start_beats(), quarter_note());
/* _length doesn't change for audio-locked regions. update length_beats to match. */
_length_beats = _session.tempo_map().quarter_note_at_sample (_position + _length) - quarter_note();
s_and_l.add (Properties::start);
s_and_l.add (Properties::length_beats);
send_change (s_and_l);
return;
}
Region::update_after_tempo_map_change (false);
/* _start has now been updated. */
_length = max ((samplecnt_t) 1, _session.tempo_map().samples_between_quarter_notes (quarter_note(), quarter_note() + _length_beats));
if (old_start != _start) {
s_and_l.add (Properties::start);
}
if (old_length != _length) {
s_and_l.add (Properties::length);
}
if (old_pos != _position) {
s_and_l.add (Properties::position);
}
send_change (s_and_l);
}
void
MidiRegion::update_length_beats (const int32_t sub_num)
{
_length_beats = _session.tempo_map().exact_qn_at_sample (_position + _length, sub_num) - quarter_note();
}
void
MidiRegion::set_position_internal (timepos_t const & pos, bool allow_bbt_recompute, const int32_t sub_num)
{
Region::set_position_internal (pos, allow_bbt_recompute, sub_num);
/* don't clobber _start _length and _length_beats if session loading.*/
if (_session.loading()) {
return;
}
/* set _start to new position in tempo map */
_start = _session.tempo_map().samples_between_quarter_notes (quarter_note() - start_beats(), quarter_note());
/* in construction from src */
if (_length_beats == 0.0) {
update_length_beats (sub_num);
}
if (position_lock_style() == AudioTime) {
_length_beats = _session.tempo_map().quarter_note_at_sample (_position + _length) - quarter_note();
} else {
/* leave _length_beats alone, and change _length to reflect the state of things
at the new position (tempo map may dictate a different number of samples).
*/
Region::set_length_internal (_session.tempo_map().samples_between_quarter_notes (quarter_note(), quarter_note() + length_beats()), sub_num);
}
}
samplecnt_t
MidiRegion::read_at (Evoral::EventSink<samplepos_t>& out, MidiRegion::read_at (Evoral::EventSink<samplepos_t>& out,
samplepos_t position, timepos_t const & position,
samplecnt_t dur, timecnt_t const & dur,
Evoral::Range<samplepos_t>* loop_range, Temporal::Range* loop_range,
MidiCursor& cursor, MidiCursor& cursor,
uint32_t chan_n, uint32_t chan_n,
NoteMode mode, NoteMode mode,
MidiStateTracker* tracker, MidiStateTracker* tracker,
MidiChannelFilter* filter) const MidiChannelFilter* filter) const
{ {
return _read_at (_sources, out, position, dur, loop_range, cursor, chan_n, mode, tracker, filter); return _read_at (_sources, out, position, dur, loop_range, cursor, chan_n, mode, tracker, filter);
} }
samplecnt_t timecnt_t
MidiRegion::master_read_at (MidiRingBuffer<samplepos_t>& out, MidiRegion::master_read_at (MidiRingBuffer<samplepos_t>& out,
samplepos_t position, timepos_t const & position,
samplecnt_t dur, timecnt_t const & dur,
Evoral::Range<samplepos_t>* loop_range, Temporal::Range* loop_range,
MidiCursor& cursor, MidiCursor& cursor,
uint32_t chan_n, uint32_t chan_n,
NoteMode mode) const NoteMode mode) const
{ {
return _read_at (_master_sources, out, position, dur, loop_range, cursor, chan_n, mode); /* no tracker */ return _read_at (_master_sources, out, position, dur, loop_range, cursor, chan_n, mode); /* no tracker */
} }
samplecnt_t timecnt_t
MidiRegion::_read_at (const SourceList& /*srcs*/, MidiRegion::_read_at (const SourceList& /*srcs*/,
Evoral::EventSink<samplepos_t>& dst, Evoral::EventSink<samplepos_t>& dst,
samplepos_t position, timepos_t const & position,
samplecnt_t dur, timecnt_t const & xdur,
Evoral::Range<samplepos_t>* loop_range, Temporal::Range* loop_range,
MidiCursor& cursor, MidiCursor& cursor,
uint32_t chan_n, uint32_t chan_n,
NoteMode mode, NoteMode mode,
MidiStateTracker* tracker, MidiStateTracker* tracker,
MidiChannelFilter* filter) const MidiChannelFilter* filter) const
{ {
sampleoffset_t internal_offset = 0; timecnt_t dur (xdur);
samplecnt_t to_read = 0; timecnt_t internal_offset;
timecnt_t to_read;
/* precondition: caller has verified that we cover the desired section */ /* precondition: caller has verified that we cover the desired section */
assert(chan_n == 0); assert(chan_n == 0);
if (muted()) { if (muted()) {
return 0; /* read nothing */ return timecnt_t(); /* read nothing */
} }
if (position < _position) { if (position < _position) {
/* we are starting the read from before the start of the region */ /* we are starting the read from before the start of the region */
internal_offset = 0; internal_offset = 0;
dur -= _position - position; dur -= position.distance (_position);
} else { } else {
/* we are starting the read from after the start of the region */ /* we are starting the read from after the start of the region */
internal_offset = position - _position; internal_offset = _position.val().distance (position);
} }
if (internal_offset >= _length) { if (internal_offset >= _length) {
return 0; /* read nothing */ return timecnt_t(); /* read nothing */
} }
if ((to_read = min (dur, _length - internal_offset)) == 0) { if ((to_read = min (dur, _length - internal_offset)) == 0) {
return 0; /* read nothing */ return timecnt_t(); /* read nothing */
} }
boost::shared_ptr<MidiSource> src = midi_source(chan_n); boost::shared_ptr<MidiSource> src = midi_source(chan_n);
@ -416,18 +263,16 @@ MidiRegion::_read_at (const SourceList& /*srcs*/,
if (src->midi_read ( if (src->midi_read (
lm, // source lock lm, // source lock
dst, // destination buffer dst, // destination buffer
_position - _start, // start position of the source in session samples _position.val().earlier (_start.val()), // start position of the source on timeline
_start + internal_offset, // where to start reading in the source _start.val() + internal_offset, // where to start reading in the source
to_read, // read duration in samples to_read, // read duration in samples
loop_range, loop_range,
cursor, cursor,
tracker, tracker,
filter, filter,
_filtered_parameters, _filtered_parameters
quarter_note(),
_start_beats
) != to_read) { ) != to_read) {
return 0; /* "read nothing" */ return timecnt_t(); /* "read nothing" */
} }
return to_read; return to_read;
@ -440,7 +285,7 @@ MidiRegion::render (Evoral::EventSink<samplepos_t>& dst,
NoteMode mode, NoteMode mode,
MidiChannelFilter* filter) const MidiChannelFilter* filter) const
{ {
sampleoffset_t internal_offset = 0; timecnt_t internal_offset;
/* precondition: caller has verified that we cover the desired section */ /* precondition: caller has verified that we cover the desired section */
@ -453,12 +298,12 @@ MidiRegion::render (Evoral::EventSink<samplepos_t>& dst,
/* dump pulls from zero to infinity ... */ /* dump pulls from zero to infinity ... */
if (_position) { if (!_position.val().zero()) {
/* we are starting the read from before the start of the region */ /* we are starting the read from before the start of the region */
internal_offset = 0; internal_offset = 0;
} else { } else {
/* we are starting the read from after the start of the region */ /* we are starting the read from after the start of the region */
internal_offset = -_position; internal_offset = timecnt_t (-_position.val());
} }
if (internal_offset >= _length) { if (internal_offset >= _length) {
@ -492,22 +337,21 @@ MidiRegion::render (Evoral::EventSink<samplepos_t>& dst,
src->midi_read ( src->midi_read (
lm, // source lock lm, // source lock
dst, // destination buffer dst, // destination buffer
_position - _start, // start position of the source in session samples this->source_position(), // start position of the source in session samples
_start + internal_offset, // where to start reading in the source this->nt_start() + internal_offset, // where to start reading in the source
_length, // length to read _length, // length to read
0, 0,
cursor, cursor,
&tracker, &tracker,
filter, filter,
_filtered_parameters, _filtered_parameters);
quarter_note(),
_start_beats);
/* resolve any notes that were "cut off" by the end of the region. The /* resolve any notes that were "cut off" by the end of the region. The
* Note-Off's get inserted at the end of the region * Note-Off's get inserted at the end of the region
*/ */
tracker.resolve_notes (dst, (_position - _start) + (_start + internal_offset + _length)); const timepos_t end = source_position() + nt_start() + internal_offset + nt_length();
tracker.resolve_notes (dst, end.samples());
return 0; return 0;
} }
@ -639,7 +483,7 @@ MidiRegion::model_contents_changed ()
} }
void void
MidiRegion::model_shifted (double qn_distance) MidiRegion::model_shifted (timecnt_t distance)
{ {
if (!model()) { if (!model()) {
return; return;
@ -647,11 +491,8 @@ MidiRegion::model_shifted (double qn_distance)
if (!_ignore_shift) { if (!_ignore_shift) {
PropertyChange what_changed; PropertyChange what_changed;
_start_beats += qn_distance; _start += distance;
samplepos_t const new_start = _session.tempo_map().samples_between_quarter_notes (_quarter_note - _start_beats, _quarter_note);
_start = new_start;
what_changed.add (Properties::start); what_changed.add (Properties::start);
what_changed.add (Properties::start_beats);
what_changed.add (Properties::contents); what_changed.add (Properties::contents);
send_change (what_changed); send_change (what_changed);
} else { } else {
@ -690,90 +531,11 @@ MidiRegion::model_automation_state_changed (Evoral::Parameter const & p)
void void
MidiRegion::fix_negative_start () MidiRegion::fix_negative_start ()
{ {
BeatsSamplesConverter c (_session.tempo_map(), _position);
_ignore_shift = true; _ignore_shift = true;
model()->insert_silence_at_start (Temporal::Beats (- _start_beats)); model()->insert_silence_at_start (-_start.val().beats());
_start = 0; _start = timecnt_t::zero_at (_start.val().time_domain(), nt_position());
_start_beats = 0.0;
}
void
MidiRegion::set_start_internal (samplecnt_t s, const int32_t sub_num)
{
Region::set_start_internal (s, sub_num);
set_start_beats_from_start_samples ();
}
void
MidiRegion::trim_to_internal (timepos_t const & position, samplecnt_t length, const int32_t sub_num)
{
if (locked()) {
return;
}
PropertyChange what_changed;
/* Set position before length, otherwise for MIDI regions this bad thing happens:
* 1. we call set_length_internal; length in beats is computed using the region's current
* (soon-to-be old) position
* 2. we call set_position_internal; position is set and length in samples re-computed using
* length in beats from (1) but at the new position, which is wrong if the region
* straddles a tempo/meter change.
*/
if (_position != position) {
const double pos_qn = _session.tempo_map().exact_qn_at_sample (position, sub_num);
const double old_pos_qn = quarter_note();
/* sets _pulse to new position.*/
set_position_internal (position, true, sub_num);
what_changed.add (Properties::position);
double new_start_qn = start_beats() + (pos_qn - old_pos_qn);
samplepos_t new_start = _session.tempo_map().samples_between_quarter_notes (pos_qn - new_start_qn, pos_qn);
if (!verify_start_and_length (new_start, length)) {
return;
}
_start_beats = new_start_qn;
what_changed.add (Properties::start_beats);
set_start_internal (new_start, sub_num);
what_changed.add (Properties::start);
}
if (_length != length) {
if (!verify_start_and_length (_start, length)) {
return;
}
set_length_internal (length, sub_num);
what_changed.add (Properties::length);
what_changed.add (Properties::length_beats);
}
set_whole_file (false);
PropertyChange start_and_length;
start_and_length.add (Properties::start);
start_and_length.add (Properties::length);
if (what_changed.contains (start_and_length)) {
first_edit ();
}
if (!what_changed.empty()) {
send_change (what_changed);
}
} }
bool bool

View file

@ -87,7 +87,7 @@ MIDISceneChanger::gather (const Locations::LocationList& locations)
have_seen_bank_changes = true; have_seen_bank_changes = true;
} }
scenes.insert (std::make_pair ((*l)->start(), msc)); scenes.insert (std::make_pair ((*l)->start_sample(), msc));
} }
} }
} }
@ -314,7 +314,7 @@ MIDISceneChanger::program_change_input (MIDI::Parser& parser, MIDI::byte program
return; return;
} }
loc = new Location (_session, time, time, new_name, Location::IsMark, 0); loc = new Location (_session, timepos_t (time), timepos_t (time), new_name, Location::IsMark);
new_mark = true; new_mark = true;
} }
@ -356,7 +356,7 @@ MIDISceneChanger::jump_to (int bank, int program)
{ {
const Locations::LocationList& locations (_session.locations()->list()); const Locations::LocationList& locations (_session.locations()->list());
boost::shared_ptr<SceneChange> sc; boost::shared_ptr<SceneChange> sc;
samplepos_t where = max_samplepos; timepos_t where = timepos_t::max (Temporal::AudioTime);
for (Locations::LocationList::const_iterator l = locations.begin(); l != locations.end(); ++l) { for (Locations::LocationList::const_iterator l = locations.begin(); l != locations.end(); ++l) {
@ -370,7 +370,7 @@ MIDISceneChanger::jump_to (int bank, int program)
} }
} }
if (where != max_samplepos) { if (where != timepos_t::max (Temporal::AudioTime)) {
_session.request_locate (where); _session.request_locate (where.samples());
} }
} }

View file

@ -168,65 +168,36 @@ MidiSource::set_state (const XMLNode& node, int /*version*/)
return 0; return 0;
} }
bool
MidiSource::empty () const
{
return !_length_beats;
}
samplecnt_t
MidiSource::length (samplepos_t pos) const
{
if (!_length_beats) {
return 0;
}
BeatsSamplesConverter converter(_session.tempo_map(), pos);
return converter.to(_length_beats);
}
void
MidiSource::update_length (samplecnt_t)
{
// You're not the boss of me!
}
void void
MidiSource::invalidate (const Lock& lock) MidiSource::invalidate (const Lock& lock)
{ {
Invalidated(_session.transport_rolling()); Invalidated(_session.transport_rolling());
} }
samplecnt_t timecnt_t
MidiSource::midi_read (const Lock& lm, MidiSource::midi_read (const Lock& lm,
Evoral::EventSink<samplepos_t>& dst, Evoral::EventSink<samplepos_t>& dst,
samplepos_t source_start, timepos_t const & source_start,
samplepos_t start, timecnt_t const & start,
samplecnt_t cnt, timecnt_t const & cnt,
Evoral::Range<samplepos_t>* loop_range, Temporal::Range* loop_range,
MidiCursor& cursor, MidiCursor& cursor,
MidiStateTracker* tracker, MidiStateTracker* tracker,
MidiChannelFilter* filter, MidiChannelFilter* filter,
const std::set<Evoral::Parameter>& filtered, const std::set<Evoral::Parameter>& filtered)
const double pos_beats,
const double start_beats) const
{ {
BeatsSamplesConverter converter(_session.tempo_map(), source_start);
const double start_qn = pos_beats - start_beats;
DEBUG_TRACE (DEBUG::MidiSourceIO, DEBUG_TRACE (DEBUG::MidiSourceIO,
string_compose ("MidiSource::midi_read() %5 sstart %1 start %2 cnt %3 tracker %4\n", string_compose ("MidiSource::midi_read() %5 sstart %1 start %2 cnt %3 tracker %4\n",
source_start, start, cnt, tracker, name())); source_start, start, cnt, tracker, name()));
if (!_model) { if (!_model) {
return read_unlocked (lm, dst, source_start, start, cnt, loop_range, tracker, filter); return timecnt_t (read_unlocked (lm, dst, source_start, start, cnt, loop_range, tracker, filter), start.position());
} }
// Find appropriate model iterator // Find appropriate model iterator
Evoral::Sequence<Temporal::Beats>::const_iterator& i = cursor.iter;
const bool linear_read = cursor.last_read_end != 0 && start == cursor.last_read_end; const bool linear_read = cursor.last_read_end != 0 && start == cursor.last_read_end;
if (!linear_read || !i.valid()) { if (!linear_read || !cursor.iter.valid()) {
/* Cached iterator is invalid, search for the first event past start. /* Cached iterator is invalid, search for the first event past start.
Note that multiple tracks can use a MidiSource simultaneously, so Note that multiple tracks can use a MidiSource simultaneously, so
all playback state must be in parameters (the cursor) and must not all playback state must be in parameters (the cursor) and must not
@ -234,64 +205,76 @@ MidiSource::midi_read (const Lock& lm,
See http://tracker.ardour.org/view.php?id=6541 See http://tracker.ardour.org/view.php?id=6541
*/ */
cursor.connect(Invalidated); cursor.connect(Invalidated);
cursor.iter = _model->begin(converter.from(start), false, filtered, &cursor.active_notes); cursor.iter = _model->begin (start.beats(), false, filtered, &cursor.active_notes);
cursor.active_notes.clear(); cursor.active_notes.clear();
} }
cursor.last_read_end = start + cnt; cursor.last_read_end = start + cnt;
// Find appropriate model iterator
Evoral::Sequence<Temporal::Beats>::const_iterator& i = cursor.iter;
// Copy events in [start, start + cnt) into dst // Copy events in [start, start + cnt) into dst
const Temporal::Beats source_start_beats = source_start.beats();
const Temporal::Beats region_start_beats = start.beats();
const Temporal::Beats cnt_beats = cnt.beats ();
const Temporal::Beats end = source_start_beats + region_start_beats + cnt_beats;
const Temporal::Beats session_source_start = (source_start + start).beats();
for (; i != _model->end(); ++i) { for (; i != _model->end(); ++i) {
// Offset by source start to convert event time to session time // Offset by source start to convert event time to session time
samplepos_t time_samples = _session.tempo_map().sample_at_quarter_note (i->time().to_double() + start_qn); const Temporal::Beats session_event_beats = source_start_beats + i->time();
if (time_samples < start + source_start) { if (session_event_beats < session_source_start) {
/* event too early */ /* event too early */
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("%1: skip event, too early @ %2 for %3\n", _name, session_event_beats, session_source_start));
continue; continue;
} else if (time_samples >= start + cnt + source_start) { } else if (session_event_beats >= end) {
DEBUG_TRACE (DEBUG::MidiSourceIO, DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("%1: reached end (%2) with event @ %3\n", _name, end, session_event_beats));
string_compose ("%1: reached end with event @ %2 vs. %3\n",
_name, time_samples, start+cnt));
break; break;
} else { } else {
/* in range */ /* in range */
timepos_t seb = timepos_t (session_event_beats);
samplepos_t time_samples = seb.samples();
if (loop_range) { if (loop_range) {
time_samples = loop_range->squish (time_samples); time_samples = loop_range->squish (seb).samples();
} }
const uint8_t status = i->buffer()[0]; const uint8_t status = i->buffer()[0];
const bool is_channel_event = (0x80 <= (status & 0xF0)) && (status <= 0xE0); const bool is_channel_event = (0x80 <= (status & 0xF0)) && (status <= 0xE0);
if (filter && is_channel_event) { if (filter && is_channel_event) {
/* Copy event so the filter can modify the channel. I'm not /* Copy event so the filter can modify the channel. I'm not
sure if this is necessary here (channels are mapped later in * sure if this is necessary here (channels are mapped later in
buffers anyway), but it preserves existing behaviour without * buffers anyway), but it preserves existing behaviour without
destroying events in the model during read. */ * destroying events in the model during read.
*/
Evoral::Event<Temporal::Beats> ev(*i, true); Evoral::Event<Temporal::Beats> ev(*i, true);
if (!filter->filter(ev.buffer(), ev.size())) { if (!filter->filter(ev.buffer(), ev.size())) {
dst.write (time_samples, ev.event_type(), ev.size(), ev.buffer()); dst.write (time_samples, ev.event_type(), ev.size(), ev.buffer());
} else { } else {
DEBUG_TRACE (DEBUG::MidiSourceIO, DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("%1: filter event @ %2 type %3 size %4\n", _name, time_samples, i->event_type(), i->size()));
string_compose ("%1: filter event @ %2 type %3 size %4\n",
_name, time_samples, i->event_type(), i->size()));
} }
} else { } else {
dst.write (time_samples, i->event_type(), i->size(), i->buffer()); dst.write (time_samples, i->event_type(), i->size(), i->buffer());
} }
#ifndef NDEBUG #ifndef NDEBUG
if (DEBUG_ENABLED(DEBUG::MidiSourceIO)) { if (DEBUG_ENABLED(DEBUG::MidiSourceIO)) {
DEBUG_STR_DECL(a); DEBUG_STR_DECL(a);
DEBUG_STR_APPEND(a, string_compose ("%1 added event @ %2 sz %3 within %4 .. %5 ", DEBUG_STR_APPEND(a, string_compose ("%1 added event @ %2 (%3) sz %4 within %5 .. %6 ", _name, time_samples, session_event_beats, i->size(), source_start + start, end));
_name, time_samples, i->size(),
start + source_start, start + cnt + source_start));
for (size_t n=0; n < i->size(); ++n) { for (size_t n=0; n < i->size(); ++n) {
DEBUG_STR_APPEND(a,hex); DEBUG_STR_APPEND(a,hex);
DEBUG_STR_APPEND(a,"0x"); DEBUG_STR_APPEND(a,"0x");
@ -312,18 +295,18 @@ MidiSource::midi_read (const Lock& lm,
return cnt; return cnt;
} }
samplecnt_t timecnt_t
MidiSource::midi_write (const Lock& lm, MidiSource::midi_write (const Lock& lm,
MidiRingBuffer<samplepos_t>& source, MidiRingBuffer<samplepos_t>& source,
samplepos_t source_start, timepos_t const & source_start,
samplecnt_t cnt) timecnt_t const & cnt)
{ {
const samplecnt_t ret = write_unlocked (lm, source, source_start, cnt); const timecnt_t ret = write_unlocked (lm, source, source_start, cnt);
if (cnt == max_samplecnt) { if (cnt == std::numeric_limits<timecnt_t>::max()) {
invalidate(lm); invalidate(lm);
} else { } else {
_capture_length += cnt; _capture_length += cnt.samples();
} }
return ret; return ret;
@ -356,13 +339,15 @@ MidiSource::mark_write_starting_now (samplecnt_t position,
because it is not RT-safe. because it is not RT-safe.
*/ */
set_natural_position (position); #warning NUTEMPO QUESTION should the time domain here reflect some setting for this source?
set_natural_position (timepos_t (position));
_capture_length = capture_length; _capture_length = capture_length;
_capture_loop_length = loop_length; _capture_loop_length = loop_length;
TempoMap& map (_session.tempo_map()); #warning NUTEMPO FIXME needs session to use tempo map
BeatsSamplesConverter converter(map, position); //TempoMap& map (_session.tempo_map());
_length_beats = converter.from(capture_length); //BeatsSamplesConverter converter(map, position);
//_length_beats = converter.from(capture_length);
} }
void void

View file

@ -55,21 +55,7 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
return -1; return -1;
} }
const TempoMap& tmap (session.tempo_map ()); snprintf (suffix, sizeof (suffix), "@%d", (int) floor ((_request.time_fraction.numerator()/ (double) _request.time_fraction.denominator()) * 100.0f));
/* Fraction is based on sample-time, while MIDI source
* is always using music-time. This matters in case there is
* a tempo-ramp. So we need to scale the ratio to music-time */
const double mtfrac =
tmap.framewalk_to_qn (region->position (), region->length () * _request.time_fraction).to_double ()
/
tmap.framewalk_to_qn (region->position (), region->length ()).to_double ();
/* the name doesn't need to be super-precise, but allow for 2 fractional
* digits just to disambiguate close but not identical stretches.
*/
snprintf (suffix, sizeof (suffix), "@%d", (int) floor (mtfrac * 100.0f));
string new_name = region->name(); string new_name = region->name();
string::size_type at = new_name.find ('@'); string::size_type at = new_name.find ('@');
@ -107,9 +93,6 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
boost::shared_ptr<MidiModel> new_model = new_src->model(); boost::shared_ptr<MidiModel> new_model = new_src->model();
new_model->start_write(); new_model->start_write();
const double r_start = tmap.quarter_notes_between_samples (region->position () - region->start (), region->position ());
const double r_end = r_start + tmap.quarter_notes_between_samples (region->position (), region->position () + region->length ());
#ifdef DEBUG_MIDI_STRETCH #ifdef DEBUG_MIDI_STRETCH
printf ("stretch start: %f end: %f [* %f] * %f\n", r_start, r_end, _request.time_fraction, mtfrac); printf ("stretch start: %f end: %f [* %f] * %f\n", r_start, r_end, _request.time_fraction, mtfrac);
#endif #endif
@ -119,26 +102,7 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
*/ */
for (Evoral::Sequence<MidiModel::TimeType>::const_iterator i = old_model->begin (MidiModel::TimeType(), true); i != old_model->end(); ++i) { for (Evoral::Sequence<MidiModel::TimeType>::const_iterator i = old_model->begin (MidiModel::TimeType(), true); i != old_model->end(); ++i) {
if (i->time() < r_start) { const MidiModel::TimeType new_time = i->time().operator* (_request.time_fraction);
#ifdef DEBUG_MIDI_STRETCH
cout << "SKIP EARLY EVENT " << i->time() << "\n";
#endif
continue;
}
if (i->time() > r_end) {
#ifdef DEBUG_MIDI_STRETCH
cout << "SKIP LATE EVENT " << i->time() << "\n";
continue;
#else
break;
#endif
}
#ifdef DEBUG_MIDI_STRETCH
cout << "STRETCH " << i->time() << " OFFSET FROM START @ " << r_start << " = " << (i->time() - r_start) << " TO " << (i->time() - r_start) * mtfrac << "\n";
#endif
const MidiModel::TimeType new_time = (i->time() - r_start) * mtfrac;
// FIXME: double copy // FIXME: double copy
Evoral::Event<MidiModel::TimeType> ev(*i, true); Evoral::Event<MidiModel::TimeType> ev(*i, true);
@ -154,9 +118,8 @@ MidiStretch::run (boost::shared_ptr<Region> r, Progress*)
const int ret = finish (region, nsrcs, new_name); const int ret = finish (region, nsrcs, new_name);
/* non-musical */ /* non-musical */
results[0]->set_start(0); #warning NUTEMPO FIXME do we still need this?
results[0]->set_position (r->position ()); // force updates the region's quarter-note position results[0]->set_length (r->nt_length().operator* ( _request.time_fraction));
results[0]->set_length((samplecnt_t) floor (r->length() * _request.time_fraction), 0);
return ret; return ret;
} }

View file

@ -370,8 +370,8 @@ MidiTrack::update_controls (BufferSet const& bufs)
const Evoral::Parameter param = midi_parameter(ev.buffer(), ev.size()); const Evoral::Parameter param = midi_parameter(ev.buffer(), ev.size());
const boost::shared_ptr<AutomationControl> control = automation_control (param); const boost::shared_ptr<AutomationControl> control = automation_control (param);
if (control) { if (control) {
double old = control->get_double (false, 0); double old = control->get_double (false, timepos_t::zero (true));
control->set_double (ev.value(), 0, false); control->set_double (ev.value(), timepos_t::zero (false), false);
if (old != ev.value()) { if (old != ev.value()) {
control->Changed (false, Controllable::NoGroup); control->Changed (false, Controllable::NoGroup);
} }
@ -406,9 +406,11 @@ MidiTrack::realtime_locate (bool for_loop_end)
} }
void void
MidiTrack::non_realtime_locate (samplepos_t pos) MidiTrack::non_realtime_locate (samplepos_t spos)
{ {
Track::non_realtime_locate(pos); timepos_t pos (spos);
Track::non_realtime_locate (spos);
boost::shared_ptr<MidiPlaylist> playlist = _disk_writer->midi_playlist(); boost::shared_ptr<MidiPlaylist> playlist = _disk_writer->midi_playlist();
if (!playlist) { if (!playlist) {
@ -416,7 +418,7 @@ MidiTrack::non_realtime_locate (samplepos_t pos)
} }
/* Get the top unmuted region at this position. */ /* Get the top unmuted region at this position. */
boost::shared_ptr<MidiRegion> region = boost::dynamic_pointer_cast<MidiRegion>(playlist->top_unmuted_region_at(pos)); boost::shared_ptr<MidiRegion> region = boost::dynamic_pointer_cast<MidiRegion> (playlist->top_unmuted_region_at (pos));
if (!region) { if (!region) {
return; return;
@ -433,8 +435,7 @@ MidiTrack::non_realtime_locate (samplepos_t pos)
} }
/* Update track controllers based on its "automation". */ /* Update track controllers based on its "automation". */
const samplepos_t origin = region->position() - region->start(); const timepos_t pos_beats = timepos_t (region->source_position().distance (pos).beats ()); /* relative to source start */
BeatsSamplesConverter bfc(_session.tempo_map(), origin);
for (Controls::const_iterator c = _controls.begin(); c != _controls.end(); ++c) { for (Controls::const_iterator c = _controls.begin(); c != _controls.end(); ++c) {
@ -450,7 +451,7 @@ MidiTrack::non_realtime_locate (samplepos_t pos)
if ((tcontrol = boost::dynamic_pointer_cast<MidiTrack::MidiControl>(c->second)) && if ((tcontrol = boost::dynamic_pointer_cast<MidiTrack::MidiControl>(c->second)) &&
(rcontrol = region->control(tcontrol->parameter()))) { (rcontrol = region->control(tcontrol->parameter()))) {
const Temporal::Beats pos_beats = bfc.from(pos - origin);
if (rcontrol->list()->size() > 0) { if (rcontrol->list()->size() > 0) {
tcontrol->set_value(rcontrol->list()->eval(pos_beats), Controllable::NoGroup); tcontrol->set_value(rcontrol->list()->eval(pos_beats), Controllable::NoGroup);
} }

View file

@ -26,7 +26,7 @@ using namespace PBD;
MonitorControl::MonitorControl (Session& session, std::string const & name, Monitorable& m) MonitorControl::MonitorControl (Session& session, std::string const & name, Monitorable& m)
: SlavableAutomationControl (session, MonitoringAutomation, ParameterDescriptor (MonitoringAutomation), : SlavableAutomationControl (session, MonitoringAutomation, ParameterDescriptor (MonitoringAutomation),
boost::shared_ptr<AutomationList>(new AutomationList(Evoral::Parameter(MonitoringAutomation))), boost::shared_ptr<AutomationList>(new AutomationList(Evoral::Parameter(MonitoringAutomation), Temporal::AudioTime)),
name) name)
, _monitorable (m) , _monitorable (m)

View file

@ -29,9 +29,10 @@ using namespace ARDOUR;
using namespace std; using namespace std;
#warning NUTEMPO QUESTION what time domain shoudl this really use?
MuteControl::MuteControl (Session& session, std::string const & name, Muteable& m) MuteControl::MuteControl (Session& session, std::string const & name, Muteable& m)
: SlavableAutomationControl (session, MuteAutomation, ParameterDescriptor (MuteAutomation), : SlavableAutomationControl (session, MuteAutomation, ParameterDescriptor (MuteAutomation),
boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (MuteAutomation))), boost::shared_ptr<AutomationList> (new AutomationList (Evoral::Parameter (MuteAutomation), Temporal::AudioTime)),
name) name)
, _muteable (m) , _muteable (m)
{ {
@ -189,7 +190,7 @@ MuteControl::automation_run (samplepos_t start, pframes_t len)
bool mute = false; bool mute = false;
if (list() && automation_playback()) { if (list() && automation_playback()) {
mute = list()->rt_safe_eval (start, valid) >= 0.5; mute = list()->rt_safe_eval (timepos_t (start), valid) >= 0.5;
} }
if (!valid) { if (!valid) {

View file

@ -48,7 +48,7 @@ OnsetDetector::operational_identifier()
} }
int int
OnsetDetector::run (const std::string& path, Readable* src, uint32_t channel, AnalysisFeatureList& results) OnsetDetector::run (const std::string& path, AudioReadable* src, uint32_t channel, AnalysisFeatureList& results)
{ {
current_results = &results; current_results = &results;
int ret = analyse (path, src, channel); int ret = analyse (path, src, channel);

View file

@ -151,7 +151,7 @@ Pannable::set_automation_state (AutoState state)
} }
void void
Pannable::start_touch (double when) Pannable::start_touch (timepos_t const & when)
{ {
const Controls& c (controls()); const Controls& c (controls());
@ -165,7 +165,7 @@ Pannable::start_touch (double when)
} }
void void
Pannable::stop_touch (double when) Pannable::stop_touch (timepos_t const & when)
{ {
const Controls& c (controls()); const Controls& c (controls());

View file

@ -27,7 +27,7 @@ using namespace ARDOUR;
PhaseControl::PhaseControl (Session& session, std::string const & name) PhaseControl::PhaseControl (Session& session, std::string const & name)
: AutomationControl (session, PhaseAutomation, ParameterDescriptor (PhaseAutomation), : AutomationControl (session, PhaseAutomation, ParameterDescriptor (PhaseAutomation),
boost::shared_ptr<AutomationList>(new AutomationList(Evoral::Parameter(PhaseAutomation))), boost::shared_ptr<AutomationList>(new AutomationList(Evoral::Parameter(PhaseAutomation), Temporal::AudioTime)),
name) name)
{ {
} }

File diff suppressed because it is too large Load diff

View file

@ -110,7 +110,7 @@ PlaylistFactory::create (boost::shared_ptr<const Playlist> old, string name, boo
} }
boost::shared_ptr<Playlist> boost::shared_ptr<Playlist>
PlaylistFactory::create (boost::shared_ptr<const Playlist> old, samplepos_t start, samplecnt_t cnt, string name, bool hidden) PlaylistFactory::create (boost::shared_ptr<const Playlist> old, timepos_t const & start, timepos_t const & cnt, string name, bool hidden)
{ {
boost::shared_ptr<Playlist> pl; boost::shared_ptr<Playlist> pl;
boost::shared_ptr<const AudioPlaylist> apl; boost::shared_ptr<const AudioPlaylist> apl;

Some files were not shown because too many files have changed in this diff Show more