13
0

Create a new layer if required on record to a track in stacked mode. Fixes #3391.

git-svn-id: svn://localhost/ardour2/branches/3.0@8026 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2010-11-14 15:01:53 +00:00
parent 7a25fa1beb
commit a46af0460b
12 changed files with 166 additions and 62 deletions

View File

@ -619,61 +619,65 @@ AudioStreamView::rec_peak_range_ready (nframes_t start, nframes_t cnt, boost::we
rec_data_ready_map[src] = true; rec_data_ready_map[src] = true;
if (rec_data_ready_map.size() == _trackview.track()->n_channels().n_audio()) { if (rec_data_ready_map.size() == _trackview.track()->n_channels().n_audio()) {
this->update_rec_regions (); update_rec_regions (start, cnt);
rec_data_ready_map.clear(); rec_data_ready_map.clear();
} }
} }
void void
AudioStreamView::update_rec_regions () AudioStreamView::update_rec_regions (framepos_t start, framecnt_t cnt)
{ {
if (Config->get_show_waveforms_while_recording ()) { if (!Config->get_show_waveforms_while_recording ()) {
uint32_t n = 0; return;
}
for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); uint32_t n = 0;
iter != rec_regions.end(); n++) {
list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator tmp = iter; for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) {
++tmp;
if (!canvas_item_visible (rec_rects[n].rectangle)) { list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator tmp = iter;
/* rect already hidden, this region is done */ ++tmp;
iter = tmp;
continue;
}
boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion>(iter->first); if (!canvas_item_visible (rec_rects[n].rectangle)) {
/* rect already hidden, this region is done */
iter = tmp;
continue;
}
if (!region) { boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion>(iter->first);
iter = tmp;
continue;
}
nframes_t origlen = region->length(); if (!region) {
iter = tmp;
continue;
}
if (region == rec_regions.back().first && rec_active) { nframes_t origlen = region->length();
if (last_rec_data_frame > region->start()) { if (region == rec_regions.back().first && rec_active) {
nframes_t nlen = last_rec_data_frame - region->start(); if (last_rec_data_frame > region->start()) {
if (nlen != region->length()) { nframes_t nlen = last_rec_data_frame - region->start();
region->suspend_property_changes (); if (nlen != region->length()) {
region->set_position (_trackview.track()->get_capture_start_frame(n), this);
region->set_length (nlen, this);
region->resume_property_changes ();
if (origlen == 1) { region->suspend_property_changes ();
/* our special initial length */ region->set_position (_trackview.track()->get_capture_start_frame(n), this);
add_region_view_internal (region, false, true); region->set_length (nlen, this);
} region->resume_property_changes ();
/* also update rect */ if (origlen == 1) {
ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle; /* our special initial length */
gdouble xend = _trackview.editor().frame_to_pixel (region->position() + region->length()); add_region_view_internal (region, false, true);
rect->property_x2() = xend; setup_new_rec_layer_time (region);
} }
check_record_layers (region, (region->position() - region->start() + start + cnt));
/* also update rect */
ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle;
gdouble xend = _trackview.editor().frame_to_pixel (region->position() + region->length());
rect->property_x2() = xend;
} }
} else { } else {

View File

@ -79,7 +79,7 @@ class AudioStreamView : public StreamView
private: private:
void setup_rec_box (); void setup_rec_box ();
void rec_peak_range_ready (nframes_t start, nframes_t cnt, boost::weak_ptr<ARDOUR::Source> src); void rec_peak_range_ready (nframes_t start, nframes_t cnt, boost::weak_ptr<ARDOUR::Source> src);
void update_rec_regions (); void update_rec_regions (ARDOUR::framepos_t, ARDOUR::framecnt_t);
RegionView* add_region_view_internal (boost::shared_ptr<ARDOUR::Region>, bool wait_for_waves, bool recording = false); RegionView* add_region_view_internal (boost::shared_ptr<ARDOUR::Region>, bool wait_for_waves, bool recording = false);
void remove_region_view (boost::weak_ptr<ARDOUR::Region> ); void remove_region_view (boost::weak_ptr<ARDOUR::Region> );

View File

@ -3152,6 +3152,8 @@ MidiRegionView::data_recorded (boost::shared_ptr<MidiBuffer> buf, boost::weak_pt
MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (&trackview); MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (&trackview);
BeatsFramesConverter converter (trackview.session()->tempo_map(), mtv->midi_track()->get_capture_start_frame (0)); BeatsFramesConverter converter (trackview.session()->tempo_map(), mtv->midi_track()->get_capture_start_frame (0));
framepos_t back = max_framepos;
for (MidiBuffer::iterator i = buf->begin(); i != buf->end(); ++i) { for (MidiBuffer::iterator i = buf->begin(); i != buf->end(); ++i) {
Evoral::MIDIEvent<MidiBuffer::TimeType> const ev (*i, false); Evoral::MIDIEvent<MidiBuffer::TimeType> const ev (*i, false);
assert (ev.buffer ()); assert (ev.buffer ());
@ -3176,5 +3178,9 @@ MidiRegionView::data_recorded (boost::shared_ptr<MidiBuffer> buf, boost::weak_pt
} else if (ev.type() == MIDI_CMD_NOTE_OFF) { } else if (ev.type() == MIDI_CMD_NOTE_OFF) {
resolve_note (ev.note (), time_beats); resolve_note (ev.note (), time_beats);
} }
back = ev.time ();
} }
midi_stream_view()->check_record_layers (region(), back);
} }

View File

@ -201,7 +201,7 @@ MidiStreamView::display_region(MidiRegionView* region_view, bool load_model)
source->model()->highest_note()); source->model()->highest_note());
// Display region contents // Display region contents
region_view->set_height(height); region_view->set_height (child_height());
region_view->display_model(source->model()); region_view->display_model(source->model());
} }
@ -294,7 +294,7 @@ void
MidiStreamView::update_contents_height () MidiStreamView::update_contents_height ()
{ {
StreamView::update_contents_height(); StreamView::update_contents_height();
_note_lines->property_y2() = height; _note_lines->property_y2() = child_height ();
apply_note_range (lowest_note(), highest_note(), true); apply_note_range (lowest_note(), highest_note(), true);
} }
@ -312,7 +312,7 @@ MidiStreamView::draw_note_lines()
_note_lines->clear(); _note_lines->clear();
if(height < 140){ if (child_height() < 140){
return; return;
} }
@ -364,13 +364,13 @@ MidiStreamView::apply_note_range(uint8_t lowest, uint8_t highest, bool to_region
_highest_note = highest; _highest_note = highest;
_lowest_note = lowest; _lowest_note = lowest;
int range = _highest_note - _lowest_note; int const range = _highest_note - _lowest_note;
int pixels_per_note = floor (height/range); int const pixels_per_note = floor (child_height () / range);
/* do not grow note height beyond 10 pixels */ /* do not grow note height beyond 10 pixels */
if (pixels_per_note > 10) { if (pixels_per_note > 10) {
int available_note_range = floor ((height)/10); int const available_note_range = floor (child_height() / 10);
int additional_notes = available_note_range - range; int additional_notes = available_note_range - range;
/* distribute additional notes to higher and lower ranges, clamp at 0 and 127 */ /* distribute additional notes to higher and lower ranges, clamp at 0 and 127 */
@ -469,6 +469,8 @@ MidiStreamView::setup_rec_box ()
// rec regions are destroyed in setup_rec_box // rec regions are destroyed in setup_rec_box
/* we add the region later */ /* we add the region later */
setup_new_rec_layer_time (region);
} }
/* start a new rec box */ /* start a new rec box */
@ -611,3 +613,4 @@ MidiStreamView::update_rec_box ()
MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rec_regions.back().second); MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rec_regions.back().second);
mrv->extend_active_notes (); mrv->extend_active_notes ();
} }

View File

@ -77,7 +77,7 @@ class MidiStreamView : public StreamView
void redisplay_track (); void redisplay_track ();
inline double contents_height() const inline double contents_height() const
{ return (_trackview.current_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 2); } { return (child_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 2); }
inline double note_to_y(uint8_t note) const inline double note_to_y(uint8_t note) const
{ return contents_height() { return contents_height()

View File

@ -578,7 +578,16 @@ StreamView::update_contents_height ()
} }
for (vector<RecBoxInfo>::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) { for (vector<RecBoxInfo>::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) {
i->rectangle->property_y2() = height; switch (_layer_display) {
case Overlaid:
i->rectangle->property_y2() = height;
break;
case Stacked:
/* In stacked displays, the recregion is always at the top */
i->rectangle->property_y1() = 0;
i->rectangle->property_y2() = h;
break;
}
} }
} }
@ -598,3 +607,41 @@ StreamView::update_coverage_frames ()
(*i)->update_coverage_frames (_layer_display); (*i)->update_coverage_frames (_layer_display);
} }
} }
void
StreamView::check_record_layers (boost::shared_ptr<Region> region, framepos_t to)
{
if (_new_rec_layer_time < to) {
/* The region being recorded has overlapped the start of a top-layered region, so
`fake' a new visual layer for the recording. This is only a visual thing for now,
as the proper layering will get sorted out when the recorded region is added to
its playlist.
*/
/* Stop this happening again */
_new_rec_layer_time = max_framepos;
/* Make space in the view for the new layer */
++_layers;
/* Set the temporary region to the correct layer so that it gets drawn correctly */
region->set_layer (_layers - 1);
/* and reset the view */
update_contents_height ();
}
}
void
StreamView::setup_new_rec_layer_time (boost::shared_ptr<Region> region)
{
/* If we are in Stacked mode, we may need to (visually) create a new layer to put the
recorded region in. To work out where this needs to happen, find the start of the next
top-layered region after the start of the region we are recording and make a note of it.
*/
if (_layer_display == Stacked) {
_new_rec_layer_time = _trackview.track()->playlist()->find_next_top_layer_position (region->start());
} else {
_new_rec_layer_time = max_framepos;
}
}

View File

@ -113,6 +113,8 @@ public:
return 0; return 0;
} }
void check_record_layers (boost::shared_ptr<ARDOUR::Region>, ARDOUR::framepos_t);
sigc::signal<void,RegionView*> RegionViewAdded; sigc::signal<void,RegionView*> RegionViewAdded;
protected: protected:
@ -171,6 +173,12 @@ protected:
PBD::ScopedConnectionList rec_data_ready_connections; PBD::ScopedConnectionList rec_data_ready_connections;
nframes_t last_rec_data_frame; nframes_t last_rec_data_frame;
/* When recording, the session time at which a new layer must be created for the region
being recorded, or max_framepos if not applicable.
*/
framepos_t _new_rec_layer_time;
void setup_new_rec_layer_time (boost::shared_ptr<ARDOUR::Region>);
private: private:
void update_coverage_frames (); void update_coverage_frames ();
}; };

View File

@ -119,7 +119,7 @@ class AudioSource : virtual public Source,
int initialize_peakfile (bool newfile, std::string path); int initialize_peakfile (bool newfile, std::string path);
int build_peaks_from_scratch (); int build_peaks_from_scratch ();
int compute_and_write_peaks (Sample* buf, framepos_t first_frame, framecnt_t cnt, int compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
bool force, bool intermediate_peaks_ready_signal); bool force, bool intermediate_peaks_ready_signal);
void truncate_peakfile(); void truncate_peakfile();
@ -135,7 +135,7 @@ class AudioSource : virtual public Source,
framecnt_t npeaks, framepos_t start, framecnt_t cnt, framecnt_t npeaks, framepos_t start, framecnt_t cnt,
double samples_per_visual_peak, framecnt_t fpp) const; double samples_per_visual_peak, framecnt_t fpp) const;
int compute_and_write_peaks (Sample* buf, framepos_t first_frame, framecnt_t cnt, int compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
bool force, bool intermediate_peaks_ready_signal, bool force, bool intermediate_peaks_ready_signal,
framecnt_t frames_per_peak); framecnt_t frames_per_peak);

View File

@ -216,6 +216,8 @@ public:
return boost::shared_ptr<Crossfade> (); return boost::shared_ptr<Crossfade> ();
} }
framepos_t find_next_top_layer_position (framepos_t) const;
protected: protected:
friend class Session; friend class Session;

View File

@ -1504,6 +1504,15 @@ AudioDiskstream::transport_stopped_wallclock (struct tm& when, time_t twhen, boo
} }
i_am_the_modifier++; i_am_the_modifier++;
if (_playlist->explicit_relayering()) {
/* We are in `explicit relayering' mode, so we must specify which layer this new region
should end up on. Put it at the top.
*/
region->set_layer (_playlist->top_layer() + 1);
region->set_pending_explicit_relayer (true);
}
_playlist->add_region (region, (*ci)->start, 1, non_layered()); _playlist->add_region (region, (*ci)->start, 1, non_layered());
i_am_the_modifier--; i_am_the_modifier--;

View File

@ -648,7 +648,7 @@ AudioSource::build_peaks_from_scratch ()
goto out; goto out;
} }
framepos_t current_frame = 0; framecnt_t current_frame = 0;
framecnt_t cnt = _length; framecnt_t cnt = _length;
_peaks_built = false; _peaks_built = false;
@ -722,15 +722,16 @@ AudioSource::done_with_peakfile_writes (bool done)
_peakfile_descriptor = 0; _peakfile_descriptor = 0;
} }
/** @param first_frame Offset from the source start of the first frame to process */
int int
AudioSource::compute_and_write_peaks (Sample* buf, framepos_t first_frame, framecnt_t cnt, AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
bool force, bool intermediate_peaks_ready) bool force, bool intermediate_peaks_ready)
{ {
return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP); return compute_and_write_peaks (buf, first_frame, cnt, force, intermediate_peaks_ready, _FPP);
} }
int int
AudioSource::compute_and_write_peaks (Sample* buf, framepos_t first_frame, framecnt_t cnt, AudioSource::compute_and_write_peaks (Sample* buf, framecnt_t first_frame, framecnt_t cnt,
bool force, bool intermediate_peaks_ready, framecnt_t fpp) bool force, bool intermediate_peaks_ready, framecnt_t fpp)
{ {
Sample* buf2 = 0; Sample* buf2 = 0;

View File

@ -2981,3 +2981,27 @@ Playlist::remove_region_by_source (boost::shared_ptr<Source> s)
i = j; i = j;
} }
} }
/** Look from a session frame time and find the start time of the next region
* which is on the top layer of this playlist.
* @param t Time to look from.
* @return Position of next top-layered region, or max_framepos if there isn't one.
*/
framepos_t
Playlist::find_next_top_layer_position (framepos_t t) const
{
RegionLock rlock (const_cast<Playlist *> (this));
layer_t const top = top_layer ();
RegionList copy = regions.rlist ();
copy.sort (RegionSortByPosition ());
for (RegionList::const_iterator i = copy.begin(); i != copy.end(); ++i) {
if ((*i)->position() >= t && (*i)->layer() == top) {
return (*i)->position();
}
}
return max_framepos;
}