if (nlen != region->length()) {
- if (region->source(0)->length() >= region->start() + nlen) {
+ if (region->source_length(0) >= region->start() + nlen) {
region->freeze ();
region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this);
region_name = region_name_from_path (paths.front(), (sources.size() > 1), false);
- regions.push_back (RegionFactory::create (sources, 0, sources[0]->length(), region_name, 0,
- Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External)));
+ regions.push_back (RegionFactory::create (sources, 0, sources[0]->length(pos), region_name, 0,
+ Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External)));
} else if (target_regions == -1 || target_regions > 1) {
region_name = region_name_from_path ((*x)->path(), false, false, sources.size(), n);
- regions.push_back (RegionFactory::create (just_one, 0, (*x)->length(), region_name, 0,
- Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External)));
+ regions.push_back (RegionFactory::create (just_one, 0, (*x)->length(pos), region_name, 0,
+ Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External)));
}
}
/* don't do duplicate of the entire source if that's what is going on here */
- if (region->start() == 0 && region->length() == region->source()->length()) {
+ if (region->start() == 0 && region->length() == region->source_length(0)) {
/* XXX should link(2) to create a new inode with "path" */
return true;
}
break;
case BySourceFileLength:
- cmp = region1->source()->length() - region2->source()->length();
+ cmp = region1->source_length(0) - region2->source_length(0);
break;
case BySourceFileCreationDate:
RegionView::region_resized(what_changed);
if (what_changed & ARDOUR::PositionChanged) {
+ set_duration(_region->length(), 0);
if (_enable_display) {
redisplay_model();
}
if (nlen != region->length()) {
- if (region->source(0)->length() >= region->position() + nlen) {
+ if (region->source_length(0) >= region->position() + nlen) {
region->freeze ();
region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this);
afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
string rname = region_name_from_path (afs->path(), false);
- r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0, srclist[0]->length(), rname, 0, Region::DefaultFlags, false));
+ r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0,
+ srclist[0]->length(srclist[0]->timeline_position()),
+ rname, 0, Region::DefaultFlags, false));
_session->audition_region(r);
}
boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (src);
- if (afs && afs->length()) {
+ if (afs && afs->length(afs->timeline_position())) {
analyse_audio_file_source (afs);
}
}
}
-
nframes64_t readable_length() const { return _length; }
uint32_t n_channels() const { return 1; }
+
+ sframes_t length (sframes_t pos) const;
+ void update_length (sframes_t pos, sframes_t cnt);
virtual nframes_t available_peaks (double zoom) const;
static bool _build_missing_peakfiles;
static bool _build_peakfiles;
+ sframes_t _length;
bool _peaks_built;
mutable Glib::Mutex _peaks_ready_lock;
Glib::ustring peakpath;
AutomationList& fade_in() { return _fade_in; }
AutomationList& fade_out() { return _fade_out; }
- nframes_t set_length (nframes_t);
+ nframes_t set_xfade_length (nframes_t);
bool is_dependent() const { return true; }
bool depends_on (boost::shared_ptr<Region> other) const {
void recompute_at_start ();
void recompute_at_end ();
+
+ void set_position_internal (nframes_t pos, bool allow_bbt_recompute);
void switch_source(boost::shared_ptr<Source> source);
virtual void append_event_unlocked_frames(const Evoral::Event<nframes_t>& ev,
sframes_t position) = 0;
+
+ virtual sframes_t length (sframes_t pos) const;
+ virtual void update_length (sframes_t pos, sframes_t cnt);
virtual void mark_streaming_midi_write_started (NoteMode mode, sframes_t start_time);
virtual void mark_streaming_write_started ();
sframes_t position,
nframes_t cnt) = 0;
- std::string _captured_for;
- mutable uint32_t _read_data_count; ///< modified in read()
- mutable uint32_t _write_data_count; ///< modified in write()
+ std::string _captured_for;
+ mutable uint32_t _read_data_count; ///< modified in read()
+ mutable uint32_t _write_data_count; ///< modified in write()
boost::shared_ptr<MidiModel> _model;
bool _writing;
mutable Evoral::Sequence<double>::const_iterator _model_iter;
- mutable sframes_t _last_read_end;
+
+ mutable double _length_beats;
+ mutable sframes_t _last_read_end;
+ sframes_t _last_write_end;
private:
bool file_changed (std::string path);
nframes_t length() const { return _length; }
layer_t layer () const { return _layer; }
+ sframes_t source_length(uint32_t n) const;
+
/* these two are valid ONLY during a StateChanged signal handler */
nframes_t last_position() const { return _last_position; }
void send_change (Change);
void trim_to_internal (nframes_t position, nframes_t length, void *src);
- void set_position_internal (nframes_t pos, bool allow_bbt_recompute);
+ virtual void set_position_internal (nframes_t pos, bool allow_bbt_recompute);
bool copied() const { return _flags & Copied; }
void maybe_uncopy ();
time_t timestamp() const { return _timestamp; }
void stamp (time_t when) { _timestamp = when; }
- sframes_t length() const { return _length; }
+ virtual sframes_t length (sframes_t pos) const = 0;
+ virtual void update_length (sframes_t pos, sframes_t cnt) = 0;
virtual const Glib::ustring& path() const = 0;
std::string get_transients_path() const;
int load_transients (const std::string&);
- void update_length (sframes_t pos, sframes_t cnt);
-
- int64_t timeline_position() const { return _timeline_position; }
- virtual void set_timeline_position (int64_t pos);
+ sframes_t timeline_position() const { return _timeline_position; }
+ virtual void set_timeline_position (sframes_t pos);
void set_allow_remove_if_empty (bool yn);
DataType _type;
Flag _flags;
time_t _timestamp;
- sframes_t _length;
- int64_t _timeline_position;
+ sframes_t _timeline_position;
bool _analysed;
mutable Glib::Mutex _lock;
mutable Glib::Mutex _analysis_lock;
try {
region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (
- pending_sources, 0, first_fs->length(),
- region_name_from_path (first_fs->name(), true), 0,
- Region::Flag (Region::DefaultFlags|Region::Automatic|Region::WholeFile)));
+ pending_sources, 0, first_fs->length(first_fs->timeline_position()),
+ region_name_from_path (first_fs->name(), true), 0,
+ Region::Flag (Region::DefaultFlags|Region::Automatic|Region::WholeFile)));
region->special_set_position (0);
}
try {
region = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (
- pending_sources, 0, first_fs->length(),
+ pending_sources, 0, first_fs->length(first_fs->timeline_position()),
region_name_from_path (first_fs->name(), true)));
}
/* create a new region from all filesources, keep it private */
- boost::shared_ptr<Region> region (RegionFactory::create (srcs, 0, srcs[0]->length(),
- region_name, 0,
- (Region::Flag) (Region::WholeFile|Region::DefaultFlags),
- false));
+ boost::shared_ptr<Region> region (RegionFactory::create (srcs, 0,
+ srcs[0]->length(srcs[0]->timeline_position()),
+ region_name, 0,
+ (Region::Flag) (Region::WholeFile|Region::DefaultFlags),
+ false));
new_playlist->set_orig_diskstream_id (diskstream->id());
new_playlist->add_region (region, _session.current_start_frame());
nframes_t read_frames, nframes_t skip_frames) const
{
/* regular diskstream/butler read complete with fades etc */
- return _read_at (_sources, _length, buf, mixdown_buffer, gain_buffer, file_position, cnt, chan_n, read_frames, skip_frames, ReadOps (~0));
+ return _read_at (_sources, _length, buf, mixdown_buffer, gain_buffer,
+ file_position, cnt, chan_n, read_frames, skip_frames, ReadOps (~0));
}
nframes_t
AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
sframes_t position, nframes_t cnt, uint32_t chan_n) const
{
- return _read_at (_master_sources, _master_sources.front()->length(), buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, 0, 0);
+ return _read_at (_master_sources,
+ _master_sources.front()->length(_master_sources.front()->timeline_position()),
+ buf, mixdown_buffer, gain_buffer,
+ position, cnt, chan_n, 0, 0);
}
nframes_t
AudioSource::AudioSource (Session& s, ustring name)
: Source (s, DataType::AUDIO, name)
+ , _length (0)
{
_peaks_built = false;
_peak_byte_max = 0;
AudioSource::AudioSource (Session& s, const XMLNode& node)
: Source (s, node)
+ , _length (0)
{
_peaks_built = false;
return 0;
}
+sframes_t
+AudioSource::length (sframes_t pos) const
+{
+ return _length;
+}
+
+void
+AudioSource::update_length (sframes_t pos, sframes_t cnt)
+{
+ if (pos + cnt > _length) {
+ _length = pos + cnt;
+ }
+}
+
+
/***********************************************************************
PEAK FILE STUFF
***********************************************************************/
/* we found it in the peaks dir, so check it out */
- if (statbuf.st_size == 0 || ((nframes_t) statbuf.st_size < ((length() / _FPP) * sizeof (PeakData)))) {
+ if (statbuf.st_size == 0 || ((nframes_t) statbuf.st_size < ((length(_timeline_position) / _FPP) * sizeof (PeakData)))) {
// empty
_peaks_built = false;
} else {
nframes_t
AudioSource::available_peaks (double zoom_factor) const
{
- off_t end;
-
if (zoom_factor < _FPP) {
- return length(); // peak data will come from the audio file
+ return length(_timeline_position); // peak data will come from the audio file
}
/* peak data comes from peakfile, but the filesize might not represent
but _peak_byte_max only monotonically increases after initialization.
*/
- end = _peak_byte_max;
+ off_t end = _peak_byte_max;
return (end/sizeof(PeakData)) * _FPP;
}
layer_relation = (int32_t) (_in->layer() - _out->layer());
// Let's make sure the fade isn't too long
- set_length(_length);
+ set_xfade_length(_length);
}
_follow_overlap = yn;
if (!yn) {
- set_length (_short_xfade_length);
+ set_xfade_length (_short_xfade_length);
} else {
- set_length (_out->first_frame() + _out->length() - _in->first_frame());
+ set_xfade_length (_out->first_frame() + _out->length() - _in->first_frame());
}
StateChanged (FollowOverlapChanged);
}
nframes_t
-Crossfade::set_length (nframes_t len)
+Crossfade::set_xfade_length (nframes_t len)
{
nframes_t limit = 0;
{
return (_flags & Removable)
&& ( (_flags & RemoveAtDestroy)
- || ((_flags & RemovableIfEmpty) && length() == 0));
+ || ((_flags & RemovableIfEmpty) && length(timeline_position()) == 0));
}
int
FileSource::init (const ustring& pathstr, bool must_exist)
{
- _length = 0;
_timeline_position = 0;
if (!find (_type, pathstr, must_exist, _file_is_new, _channel)) {
{
}
+void
+MidiRegion::set_position_internal (nframes_t pos, bool allow_bbt_recompute)
+{
+ BeatsFramesConverter old_converter(_session, _position - _start);
+ double length_beats = old_converter.from(_length);
+
+ Region::set_position_internal(pos, allow_bbt_recompute);
+
+ BeatsFramesConverter new_converter(_session, pos - _start);
+
+ set_length(new_converter.to(length_beats), 0);
+}
+
nframes_t
MidiRegion::read_at (MidiRingBuffer<nframes_t>& out, sframes_t position, nframes_t dur, uint32_t chan_n, NoteMode mode) const
{
, _read_data_count(0)
, _write_data_count(0)
, _writing (false)
+ , _length_beats(0.0)
, _last_read_end(0)
+ , _last_write_end(0)
{
}
, _read_data_count(0)
, _write_data_count(0)
, _writing (false)
+ , _length_beats(0.0)
, _last_read_end(0)
+ , _last_write_end(0)
{
_read_data_count = 0;
_write_data_count = 0;
return 0;
}
+sframes_t
+MidiSource::length (sframes_t pos) const
+{
+ BeatsFramesConverter converter(_session, pos);
+ return converter.to(_length_beats);
+}
+
+void
+MidiSource::update_length (sframes_t pos, sframes_t cnt)
+{
+ // You're not the boss of me!
+}
+
void
MidiSource::invalidate ()
{
MidiSource::midi_write (MidiRingBuffer<nframes_t>& dst, sframes_t position, nframes_t cnt)
{
Glib::Mutex::Lock lm (_lock);
- return write_unlocked (dst, position, cnt);
+ const nframes_t ret = write_unlocked (dst, position, cnt);
+ _last_write_end = position + cnt;
+ return ret;
}
bool
_model->set_note_mode(mode);
_model->start_write();
}
-
+
+ _last_write_end = start_frame;
_writing = true;
}
void
MidiSource::mark_streaming_write_started ()
{
+ sframes_t start_frame = _session.transport_frame();
+
if (_model) {
_model->start_write();
}
+ _last_write_end = start_frame;
_writing = true;
}
MidiSource::mark_streaming_write_completed ()
{
if (_model) {
- _model->end_write(false); // FIXME: param?
+ _model->end_write(false);
}
_writing = false;
return true;
}
+sframes_t
+Region::source_length(uint32_t n) const
+{
+ return _sources[n]->length(_position - _start);
+}
+
bool
Region::verify_length (nframes_t len)
{
nframes_t maxlen = 0;
for (uint32_t n=0; n < _sources.size(); ++n) {
- maxlen = max (maxlen, (nframes_t)_sources[n]->length() - _start);
+ maxlen = max (maxlen, (nframes_t)source_length(n) - _start);
}
len = min (len, maxlen);
nframes_t maxlen = 0;
for (uint32_t n=0; n < _sources.size(); ++n) {
- maxlen = max (maxlen, (nframes_t)_sources[n]->length() - new_start);
+ maxlen = max (maxlen, (nframes_t)source_length(n) - new_start);
}
new_length = min (new_length, maxlen);
}
for (uint32_t n=0; n < _sources.size(); ++n) {
- if (pos > _sources[n]->length() - _length) {
+ if (pos > source_length(n) - _length) {
return false;
}
}
}
for (uint32_t n=0; n < _sources.size(); ++n) {
- if (new_start > _sources[n]->length() - _length) {
- new_start = _sources[n]->length() - _length;
+ if (new_start > source_length(n) - _length) {
+ new_start = source_length(n) - _length;
}
}
return true;
*/
if ((other = boost::dynamic_pointer_cast<AudioRegion>(region)) != 0) {
- AudioRegion* ar = new AudioRegion (other, srcs, srcs.front()->length(), name, layer, flags);
+ AudioRegion* ar = new AudioRegion (other, srcs, srcs.front()->length(srcs.front()->timeline_position()), name, layer, flags);
boost::shared_ptr<AudioRegion> arp (ar);
boost::shared_ptr<Region> ret (boost::static_pointer_cast<Region> (arp));
if (announce) {
/* construct a region to represent the bounced material */
- result = RegionFactory::create (srcs, 0, srcs.front()->length(),
- region_name_from_path (srcs.front()->name(), true));
+ result = RegionFactory::create (srcs, 0,
+ srcs.front()->length(srcs.front()->timeline_position()),
+ region_name_from_path (srcs.front()->name(), true));
}
out:
boost::shared_ptr<AudioFileSource> fs;
if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (siter->second)) != 0) {
if (!fs->destructive()) {
- if (fs->length() == 0) {
+ if (fs->length(fs->timeline_position()) == 0) {
continue;
}
}
capture files.
*/
- if (!i->second->used() && i->second->length() > 0) {
+ if (!i->second->used() && i->second->length(i->second->timeline_position()) > 0) {
dead_sources.push_back (i->second);
i->second->GoingAway();
}
_model->start_write();
}
- Evoral::MIDIEvent<nframes_t> ev(0, 0.0, 4, NULL, true);
+ Evoral::MIDIEvent<nframes_t> ev;
while (true) {
bool ret = src.peek_time(&time);
- if (!ret || time - position > _length + dur) {
+ if (!ret || time > _last_write_end + dur) {
break;
}
ret = src.read_prefix(&time, &type, &size);
if (!ret) {
+ cerr << "ERROR: Unable to read event prefix, corrupt MIDI ring buffer" << endl;
break;
}
Evoral::SMF::flush();
free(buf);
- const sframes_t oldlen = _length;
- update_length(oldlen, dur);
-
- ViewDataRangeReady(position + oldlen, dur); /* EMIT SIGNAL */
+ ViewDataRangeReady(position + _last_write_end, dur); /* EMIT SIGNAL */
return dur;
}
return;
}
+ _length_beats = max(_length_beats, ev.time());
+
const double delta_time_beats = ev.time() - _last_ev_time_beats;
const uint32_t delta_time_ticks = (uint32_t)lrint(delta_time_beats * (double)ppqn());
BeatsFramesConverter converter(_session, position);
+ _length_beats = max(_length_beats, converter.from(ev.time()));
+
const sframes_t delta_time_frames = ev.time() - _last_ev_time_frames;
const double delta_time_beats = converter.from(delta_time_frames);
const uint32_t delta_time_ticks = (uint32_t)(lrint(delta_time_beats * (double)ppqn()));
scratch_size = ev.size();
}
ev.size() = scratch_size; // ensure read_event only allocates if necessary
+
+ _length_beats = max(_length_beats, ev.time());
}
set_default_controls_interpolation();
{
_analysed = false;
_timestamp = 0;
- _length = 0;
_in_use = 0;
}
, _timeline_position(0)
{
_timestamp = 0;
- _length = 0;
_analysed = false;
_in_use = 0;
return 0;
}
-void
-Source::update_length (sframes_t pos, sframes_t cnt)
-{
- if (pos + cnt > _length) {
- _length = pos + cnt;
- }
-}
-
void
Source::add_playlist (boost::shared_ptr<Playlist> pl)
{