latched rec-enable
[ardour.git] / gtk2_ardour / streamview.cc
1 #include <cmath>
2
3 #include <gtkmm.h>
4
5 #include <gtkmm2ext/gtk_ui.h>
6
7 #include <ardour/audioplaylist.h>
8 #include <ardour/audioregion.h>
9 #include <ardour/diskstream.h>
10 #include <ardour/audio_track.h>
11 #include <ardour/playlist_templates.h>
12 #include <ardour/source.h>
13
14 #include "streamview.h"
15 #include "regionview.h"
16 #include "audio_time_axis.h"
17 #include "canvas-waveview.h"
18 #include "canvas-simplerect.h"
19 #include "region_selection.h"
20 #include "selection.h"
21 #include "public_editor.h"
22 #include "ardour_ui.h"
23 #include "crossfade_view.h"
24 #include "rgb_macros.h"
25 #include "gui_thread.h"
26 #include "utils.h"
27
28 using namespace ARDOUR;
29 using namespace Editing;
30
31 StreamView::StreamView (AudioTimeAxisView& tv)
32         : _trackview (tv)
33 {
34         region_color = _trackview.color();
35         crossfades_visible = true;
36
37         if (tv.is_audio_track()) {
38                 /* TRACK */
39                 //stream_base_color = RGBA_TO_UINT (222,223,218,255);
40                 stream_base_color = color_map[cAudioTrackBase];
41         } else {
42                 /* BUS */
43                 //stream_base_color = RGBA_TO_UINT (230,226,238,255);
44                 stream_base_color = color_map[cAudioBusBase];
45         }
46
47         /* set_position() will position the group */
48
49         //GTK2FIX -- how to get the group? is the canvas display really a group?
50         //canvas_group = gnome_canvas_item_new (GNOME_CANVAS_GROUP(_trackview.canvas_display),
51         //                          gnome_canvas_group_get_type (),
52         //                          NULL);
53         canvas_group = new ArdourCanvas::Group(*_trackview.canvas_display);
54
55         //canvas_rect = gnome_canvas_item_new (GNOME_CANVAS_GROUP(canvas_group),
56         //                         gnome_canvas_simplerect_get_type(),
57         //                         "x1", 0.0,
58         //                         "y1", 0.0,
59         //                         "x2", 1000000.0,
60         //                         "y2", (double) tv.height,
61         //                         "outline_color_rgba", color_map[cAudioTrackOutline],
62         //                         /* outline ends and bottom */
63         //                         "outline_what", (guint32) (0x1|0x2|0x8),
64         //                         "fill_color_rgba", stream_base_color,
65         //      ]                  NULL);
66         canvas_rect = new ArdourCanvas::SimpleRect (*canvas_group);
67         canvas_rect->property_x1() = 0.0;
68         canvas_rect->property_y1() = 0.0;
69         canvas_rect->property_x2() = 1000000.0;
70         canvas_rect->property_y2() = (double) tv.height;
71         canvas_rect->property_outline_color_rgba() = color_map[cAudioTrackOutline];
72         /* outline ends and bottom */
73         canvas_rect->property_outline_what() = (guint32) (0x1|0x2|0x8);
74         canvas_rect->property_fill_color_rgba() = stream_base_color;
75
76         canvas_rect->signal_event().connect (bind (mem_fun (_trackview.editor, &PublicEditor::canvas_stream_view_event), canvas_rect, &_trackview));
77
78         _samples_per_unit = _trackview.editor.get_current_zoom();
79         _amplitude_above_axis = 1.0;
80
81         if (_trackview.is_audio_track()) {
82                 _trackview.audio_track()->diskstream_changed.connect (mem_fun (*this, &StreamView::diskstream_changed));
83                 _trackview.session().TransportStateChange.connect (mem_fun (*this, &StreamView::transport_changed));
84                 _trackview.get_diskstream()->record_enable_changed.connect (mem_fun (*this, &StreamView::rec_enable_changed));
85                 _trackview.session().RecordStateChanged.connect (mem_fun (*this, &StreamView::sess_rec_enable_changed));
86         } 
87
88         rec_updating = false;
89         rec_active = false;
90         use_rec_regions = tv.editor.show_waveforms_recording ();
91         last_rec_peak_frame = 0;
92 }
93
94 StreamView::~StreamView ()
95 {
96         undisplay_diskstream ();
97         delete canvas_group;
98 }
99
100 void
101 StreamView::attach ()
102 {
103         if (_trackview.is_audio_track()) {
104                 display_diskstream (_trackview.get_diskstream());
105         }
106 }
107
108 int
109 StreamView::set_position (gdouble x, gdouble y)
110
111 {
112         canvas_group->property_x() = x;
113         canvas_group->property_y() = y;
114         return 0;
115 }
116
117 int
118 StreamView::set_height (gdouble h)
119 {
120         /* limit the values to something sane-ish */
121
122         if (h < 10.0 || h > 1000.0) {
123                 return -1;
124         }
125
126         canvas_rect->property_y2() = h;
127
128         for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
129                 (*i)->set_height (h);
130         }
131
132         for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
133                 (*i)->set_height (h);
134         }
135
136         for (vector<RecBoxInfo>::iterator i = rec_rects.begin(); i != rec_rects.end(); ++i) {
137                 RecBoxInfo &recbox = (*i);
138                 recbox.rectangle->property_y2() = h - 1.0;
139         }
140
141         return 0;
142 }
143
144 int 
145 StreamView::set_samples_per_unit (gdouble spp)
146 {
147         AudioRegionViewList::iterator i;
148
149         if (spp < 1.0) {
150                 return -1;
151         }
152
153         _samples_per_unit = spp;
154
155         for (i = region_views.begin(); i != region_views.end(); ++i) {
156                 (*i)->set_samples_per_unit (spp);
157         }
158
159         for (CrossfadeViewList::iterator xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) {
160                 (*xi)->set_samples_per_unit (spp);
161         }
162
163         for (vector<RecBoxInfo>::iterator xi = rec_rects.begin(); xi != rec_rects.end(); ++xi) {
164                 RecBoxInfo &recbox = (*xi);
165                 
166                 gdouble xstart = _trackview.editor.frame_to_pixel ( recbox.start );
167                 gdouble xend = _trackview.editor.frame_to_pixel ( recbox.start + recbox.length );
168
169                 recbox.rectangle->property_x1() = xstart;
170                 recbox.rectangle->property_x2() = xend;
171         }
172
173         return 0;
174 }
175
176 int 
177 StreamView::set_amplitude_above_axis (gdouble app)
178
179 {
180         AudioRegionViewList::iterator i;
181
182         if (app < 1.0) {
183                 return -1;
184         }
185
186         _amplitude_above_axis = app;
187
188         for (i = region_views.begin(); i != region_views.end(); ++i) {
189                 (*i)->set_amplitude_above_axis (app);
190         }
191
192         return 0;
193 }
194
195 void
196 StreamView::add_region_view (Region *r)
197 {
198         add_region_view_internal (r, true);
199 }
200
201 void
202 StreamView::add_region_view_internal (Region *r, bool wait_for_waves)
203 {
204         ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::add_region_view), r));
205
206         AudioRegion* region = dynamic_cast<AudioRegion*> (r);
207
208         if (region == 0) {
209                 return;
210         }
211
212         AudioRegionView *region_view;
213         list<AudioRegionView *>::iterator i;
214
215         for (i = region_views.begin(); i != region_views.end(); ++i) {
216                 if (&(*i)->region == region) {
217                         
218                         /* great. we already have a AudioRegionView for this Region. use it again.
219                          */
220
221                         (*i)->set_valid (true);
222                         return;
223                 }
224         }
225
226         region_view = new AudioRegionView (canvas_group,
227                                            _trackview,
228                                            *region,
229                                            _samples_per_unit,
230                                            _amplitude_above_axis, 
231                                            region_color, 
232                                            wait_for_waves);
233
234         region_views.push_front (region_view);
235         
236         /* follow global waveform setting */
237
238         region_view->set_waveform_visible(_trackview.editor.show_waveforms());
239
240         /* catch regionview going away */
241
242         region->GoingAway.connect (mem_fun (*this, &StreamView::remove_region_view));
243         
244         AudioRegionViewAdded (region_view);
245 }
246
247 void
248 StreamView::remove_region_view (Region *r)
249 {
250         ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::remove_region_view), r));
251
252         AudioRegion* ar = dynamic_cast<AudioRegion*> (r);
253
254         if (ar == 0) {
255                 return;
256         }
257
258         for (list<AudioRegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
259                 if (&((*i)->region) == ar) {
260                         delete *i;
261                         region_views.erase (i);
262                         break;
263                 }
264         }
265
266         for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end();) {
267                 list<CrossfadeView*>::iterator tmp;
268                 
269                 tmp = i;
270                 ++tmp;
271                 
272                 if ((*i)->crossfade.involves (*ar)) {
273                         delete *i;
274                         crossfade_views.erase (i);
275                 }
276                 
277                 i = tmp;
278         }
279 }
280
281 void
282 StreamView::remove_rec_region (Region *r)
283 {
284         ENSURE_GUI_THREAD(bind (mem_fun (*this, &StreamView::remove_rec_region), r));
285         
286         if (!Gtkmm2ext::UI::instance()->caller_is_gui_thread()) {
287                 fatal << "region deleted from non-GUI thread!" << endmsg;
288                 /*NOTREACHED*/
289         } 
290
291         AudioRegion* ar = dynamic_cast<AudioRegion*> (r);
292
293         if (ar == 0) {
294                 return;
295         }
296
297         for (list<AudioRegion *>::iterator i = rec_regions.begin(); i != rec_regions.end(); ++i) {
298                 if (*i == ar) {
299                         rec_regions.erase (i);
300                         break;
301                 }
302         }
303 }
304
305 void
306 StreamView::undisplay_diskstream ()
307 {
308         for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
309                 delete *i;
310         }
311
312         for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
313                 delete *i;
314         }
315
316         region_views.clear();
317         crossfade_views.clear ();
318 }
319
320 void
321 StreamView::display_diskstream (DiskStream *ds)
322 {
323         playlist_change_connection.disconnect();
324         playlist_changed (ds);
325         playlist_change_connection = ds->PlaylistChanged.connect (bind (mem_fun (*this, &StreamView::playlist_changed), ds));
326 }
327
328 void
329 StreamView::playlist_modified ()
330 {
331         ENSURE_GUI_THREAD (mem_fun (*this, &StreamView::playlist_modified));
332
333         /* if the playlist is modified, make sure xfades are on top and all the regionviews are stacked 
334            correctly.
335         */
336
337         for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
338                 region_layered (*i);
339         }
340
341         for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
342                 (*i)->get_canvas_group()->raise_to_top();
343         }
344 }
345
346 void
347 StreamView::playlist_changed (DiskStream *ds)
348 {
349         ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_changed), ds));
350
351         /* disconnect from old playlist */
352
353         for (vector<sigc::connection>::iterator i = playlist_connections.begin(); i != playlist_connections.end(); ++i) {
354                 (*i).disconnect();
355         }
356         
357         playlist_connections.clear();
358         undisplay_diskstream ();
359
360         /* draw it */
361
362         redisplay_diskstream ();
363
364         /* catch changes */
365
366         playlist_connections.push_back (ds->playlist()->RegionAdded.connect (mem_fun (*this, &StreamView::add_region_view)));
367         playlist_connections.push_back (ds->playlist()->RegionRemoved.connect (mem_fun (*this, &StreamView::remove_region_view)));
368         playlist_connections.push_back (ds->playlist()->StateChanged.connect (mem_fun (*this, &StreamView::playlist_state_changed)));
369         playlist_connections.push_back (ds->playlist()->Modified.connect (mem_fun (*this, &StreamView::playlist_modified)));
370         playlist_connections.push_back (ds->playlist()->NewCrossfade.connect (mem_fun (*this, &StreamView::add_crossfade)));
371 }
372
373 void
374 StreamView::add_crossfade (Crossfade *crossfade)
375 {
376         AudioRegionView* lview = 0;
377         AudioRegionView* rview = 0;
378
379         ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::add_crossfade), crossfade));
380
381         /* first see if we already have a CrossfadeView for this Crossfade */
382
383         for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
384                 if (&(*i)->crossfade == crossfade) {
385                         if (!crossfades_visible) {
386                                 (*i)->hide();
387                         } else {
388                                 (*i)->show ();
389                         }
390                         (*i)->set_valid (true);
391                         return;
392                 }
393         }
394
395         /* create a new one */
396
397         for (list<AudioRegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
398                 if (!lview && &((*i)->region) == &crossfade->out()) {
399                         lview = *i;
400                 }
401                 if (!rview && &((*i)->region) == &crossfade->in()) {
402                         rview = *i;
403                 }
404         }
405
406         CrossfadeView *cv = new CrossfadeView (_trackview.canvas_display,
407                                                _trackview,
408                                                *crossfade,
409                                                _samples_per_unit,
410                                                region_color,
411                                                *lview, *rview);
412
413         crossfade->Invalidated.connect (mem_fun (*this, &StreamView::remove_crossfade));
414         crossfade_views.push_back (cv);
415
416         if (!crossfades_visible) {
417                 cv->hide ();
418         }
419 }
420
421 void
422 StreamView::remove_crossfade (Crossfade *xfade)
423 {
424         ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::remove_crossfade), xfade));
425
426         for (list<CrossfadeView*>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
427                 if (&(*i)->crossfade == xfade) {
428                         delete *i;
429                         crossfade_views.erase (i);
430                         break;
431                 }
432         }
433 }
434
435 void
436 StreamView::playlist_state_changed (Change ignored)
437 {
438         ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::playlist_state_changed), ignored));
439
440         redisplay_diskstream ();
441 }
442
443 void
444 StreamView::redisplay_diskstream ()
445 {
446         list<AudioRegionView *>::iterator i, tmp;
447         list<CrossfadeView*>::iterator xi, tmpx;
448
449         for (i = region_views.begin(); i != region_views.end(); ++i) {
450                 (*i)->set_valid (false);
451         }
452
453         for (xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) {
454                 (*xi)->set_valid (false);
455                 if ((*xi)->visible()) {
456                         (*xi)->show ();
457                 }
458         }
459
460         if (_trackview.is_audio_track()) {
461                 _trackview.get_diskstream()->playlist()->foreach_region (this, &StreamView::add_region_view);
462                 _trackview.get_diskstream()->playlist()->foreach_crossfade (this, &StreamView::add_crossfade);
463         }
464
465         for (i = region_views.begin(); i != region_views.end(); ) {
466                 tmp = i;
467                 tmp++;
468
469                 if (!(*i)->is_valid()) {
470                         delete *i;
471                         region_views.erase (i);
472                 } 
473
474                 i = tmp;
475         }
476
477         for (xi = crossfade_views.begin(); xi != crossfade_views.end();) {
478                 tmpx = xi;
479                 tmpx++;
480
481                 if (!(*xi)->valid()) {
482                         delete *xi;
483                         crossfade_views.erase (xi);
484                 }
485
486                 xi = tmpx;
487         }
488
489         /* now fix layering */
490
491         playlist_modified ();
492 }
493
494 void
495 StreamView::diskstream_changed (void *src_ignored)
496 {
497         AudioTrack *at;
498
499         if ((at = _trackview.audio_track()) != 0) {
500                 DiskStream& ds = at->disk_stream();
501                 /* XXX grrr: when will SigC++ allow me to bind references? */
502                 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*this, &StreamView::display_diskstream), &ds));
503         } else {
504                 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::undisplay_diskstream));
505         }
506 }
507
508 void
509 StreamView::apply_color (Gdk::Color& color, ColorTarget target)
510
511 {
512         list<AudioRegionView *>::iterator i;
513
514         switch (target) {
515         case RegionColor:
516                 region_color = color;
517                 for (i = region_views.begin(); i != region_views.end(); ++i) {
518                         (*i)->set_color (region_color);
519                 }
520                 // stream_base_color = RGBA_TO_UINT (color.red/256, color.green/256, color.blue/256, 255);
521                 // gnome_canvas_item_set (canvas_rect, "fill_color_rgba", stream_base_color, NULL);
522                 break;
523                 
524         case StreamBaseColor:
525                 // stream_base_color = RGBA_TO_UINT (color.red/256, color.green/256, color.blue/256, 255);
526                 // gnome_canvas_item_set (canvas_rect, "fill_color_rgba", stream_base_color, NULL);
527                 break;
528         }
529 }
530
531 void
532 StreamView::set_show_waveforms (bool yn)
533 {
534         for (list<AudioRegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
535                         (*i)->set_waveform_visible (yn);
536         }
537 }
538
539 void
540 StreamView::set_selected_regionviews (AudioRegionSelection& regions)
541 {
542         bool selected;
543
544         for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
545                 
546                 selected = false;
547                 
548                 for (AudioRegionSelection::iterator ii = regions.begin(); ii != regions.end(); ++ii) {
549                         if (*i == *ii) {
550                                 selected = true;
551                         }
552                 }
553                 
554                 (*i)->set_selected (selected, this);
555         }
556 }
557
558 void
559 StreamView::get_selectables (jack_nframes_t start, jack_nframes_t end, list<Selectable*>& results)
560 {
561         for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
562                 if ((*i)->region.coverage(start, end) != OverlapNone) {
563                         results.push_back (*i);
564                 }
565         }
566 }
567
568 void
569 StreamView::get_inverted_selectables (Selection& sel, list<Selectable*>& results)
570 {
571         for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
572                 if (!sel.audio_regions.contains (*i)) {
573                         results.push_back (*i);
574                 }
575         }
576 }
577
578 void
579 StreamView::set_waveform_shape (WaveformShape shape)
580 {
581         for (AudioRegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
582                 (*i)->set_waveform_shape (shape);
583         }
584 }               
585                 
586 void
587 StreamView::region_layered (AudioRegionView* rv)
588 {
589         rv->get_canvas_group()->lower_to_bottom();
590
591         /* don't ever leave it at the bottom, since then it doesn't
592            get events - the  parent group does instead ...
593         */
594         
595         rv->get_canvas_group()->raise (rv->region.layer() + 1);
596 }
597
598 void
599 StreamView::rec_enable_changed (void *src)
600 {
601         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
602 }
603
604 void
605 StreamView::sess_rec_enable_changed ()
606 {
607         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
608 }
609
610 void
611 StreamView::transport_changed()
612 {
613         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &StreamView::setup_rec_box));
614 }
615
616 void
617 StreamView::setup_rec_box ()
618 {
619         // cerr << _trackview.name() << " streamview SRB\n";
620
621         if (_trackview.session().transport_rolling()) {
622
623                 // cerr << "\trolling\n";
624
625                 if (!rec_active
626                     && _trackview.session().record_status() == Session::Recording
627                     && _trackview.get_diskstream()->record_enabled()) {
628
629                         if (use_rec_regions && rec_regions.size() == rec_rects.size()) {
630                                 /* add a new region, but don't bother if they set use_rec_regions mid-record */
631
632                                 AudioRegion::SourceList sources;
633
634                                 for (list<sigc::connection>::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) {
635                                         (*prc).disconnect();
636                                 }
637                                 peak_ready_connections.clear();
638                                         
639                                 for (uint32_t n=0; n < _trackview.get_diskstream()->n_channels(); ++n) {
640                                         Source *src = (Source *) _trackview.get_diskstream()->write_source (n);
641                                         if (src) {
642                                                 sources.push_back (src);
643                                                 peak_ready_connections.push_back (src->PeakRangeReady.connect (bind (mem_fun (*this, &StreamView::rec_peak_range_ready), src))); 
644                                         }
645                                 }
646
647                                 // handle multi
648                                 
649                                 jack_nframes_t start = 0;
650                                 if (rec_regions.size() > 0) {
651                                         start = rec_regions.back()->start() + _trackview.get_diskstream()->get_captured_frames(rec_regions.size()-1);
652                                 }
653                                 
654                                 AudioRegion * region = new AudioRegion(sources, start, 1 , "", 0, (Region::Flag)(Region::DefaultFlags | Region::DoNotSaveState), false);
655                                 region->set_position (_trackview.session().transport_frame(), this);
656                                 rec_regions.push_back (region);
657                                 /* catch it if it goes away */
658                                 region->GoingAway.connect (mem_fun (*this, &StreamView::remove_rec_region));
659
660                                 /* we add the region later */
661                         }
662                         
663                         /* start a new rec box */
664
665                         AudioTrack* at;
666
667                         at = _trackview.audio_track(); /* we know what it is already */
668                         DiskStream& ds = at->disk_stream();
669                         jack_nframes_t frame_pos = ds.current_capture_start ();
670                         gdouble xstart = _trackview.editor.frame_to_pixel (frame_pos);
671                         gdouble xend = xstart;
672                         
673                         ArdourCanvas::SimpleRect * rec_rect = new Gnome::Canvas::SimpleRect (*canvas_group);
674                         rec_rect->property_x1() = xstart;
675                         rec_rect->property_y1() = 1.0;
676                         rec_rect->property_x2() = xend;
677                         rec_rect->property_y2() = (double) _trackview.height - 1;
678                         rec_rect->property_outline_color_rgba() = color_map[cRecordingRectOutline];
679                         rec_rect->property_fill_color_rgba() =  color_map[cRecordingRectFill];
680                         
681                         RecBoxInfo recbox;
682                         recbox.rectangle = rec_rect;
683                         recbox.start = _trackview.session().transport_frame();
684                         recbox.length = 0;
685                         
686                         rec_rects.push_back (recbox);
687                         
688                         screen_update_connection.disconnect();
689                         screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun (*this, &StreamView::update_rec_box));        
690                         rec_updating = true;
691                         rec_active = true;
692
693                 } else if (rec_active &&
694                            (_trackview.session().record_status() != Session::Recording ||
695                             !_trackview.get_diskstream()->record_enabled())) {
696
697                         screen_update_connection.disconnect();
698                         rec_active = false;
699                         rec_updating = false;
700
701                 }
702                 
703         } else {
704
705                 // cerr << "\tNOT rolling, rec_rects = " << rec_rects.size() << " rec_regions = " << rec_regions.size() << endl;
706
707                 if (!rec_rects.empty() || !rec_regions.empty()) {
708
709                         /* disconnect rapid update */
710                         screen_update_connection.disconnect();
711
712                         for (list<sigc::connection>::iterator prc = peak_ready_connections.begin(); prc != peak_ready_connections.end(); ++prc) {
713                                 (*prc).disconnect();
714                         }
715                         peak_ready_connections.clear();
716
717                         rec_updating = false;
718                         rec_active = false;
719                         last_rec_peak_frame = 0;
720                         
721                         /* remove temp regions */
722                         for (list<AudioRegion*>::iterator iter=rec_regions.begin(); iter != rec_regions.end(); )
723                         {
724                                 list<AudioRegion*>::iterator tmp;
725
726                                 tmp = iter;
727                                 ++tmp;
728
729                                 /* this will trigger the remove_region_view */
730                                 delete *iter;
731
732                                 iter = tmp;
733                         }
734                         
735                         rec_regions.clear();
736
737                         // cerr << "\tclear " << rec_rects.size() << " rec rects\n";
738                 
739
740                         /* transport stopped, clear boxes */
741                         for (vector<RecBoxInfo>::iterator iter=rec_rects.begin(); iter != rec_rects.end(); ++iter) {
742                                 RecBoxInfo &rect = (*iter);
743                                 delete rect.rectangle;
744                         }
745                         
746                         rec_rects.clear();
747                         
748                 }
749         }
750 }
751
752
753 void
754 StreamView::update_rec_box ()
755 {
756         /* only update the last box */
757         if (rec_active && rec_rects.size() > 0) {
758                 RecBoxInfo & rect = rec_rects.back();
759                 jack_nframes_t at = _trackview.get_diskstream()->current_capture_end();
760                 
761                 rect.length = at - rect.start;
762
763                 gdouble xstart = _trackview.editor.frame_to_pixel ( rect.start );
764                 gdouble xend = _trackview.editor.frame_to_pixel ( at );
765
766                 rect.rectangle->property_x1() = xstart;
767                 rect.rectangle->property_x2() = xend;
768         }
769 }
770
771 AudioRegionView*
772 StreamView::find_view (const AudioRegion& region)
773 {
774         for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
775
776                 if (&(*i)->region == &region) {
777                         return *i;
778                 }
779         }
780         return 0;
781 }
782         
783 void
784 StreamView::foreach_regionview (sigc::slot<void,AudioRegionView*> slot)
785 {
786         for (list<AudioRegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
787                 slot (*i);
788         }
789 }
790
791 void
792 StreamView::foreach_crossfadeview (void (CrossfadeView::*pmf)(void))
793 {
794         for (list<CrossfadeView*>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
795                 ((*i)->*pmf) ();
796         }
797 }
798
799 void
800 StreamView::rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, Source * src)
801 {
802         // this is called from the peak building thread
803
804         ENSURE_GUI_THREAD(bind (mem_fun (*this, &StreamView::rec_peak_range_ready), start, cnt, src));
805         
806         if (rec_peak_ready_map.size() == 0 || start+cnt > last_rec_peak_frame) {
807                 last_rec_peak_frame = start + cnt;
808         }
809
810         rec_peak_ready_map[src] = true;
811
812         if (rec_peak_ready_map.size() == _trackview.get_diskstream()->n_channels()) {
813                 this->update_rec_regions ();
814                 rec_peak_ready_map.clear();
815         }
816 }
817
818 void
819 StreamView::update_rec_regions ()
820 {
821         if (use_rec_regions) {
822
823                 uint32_t n = 0;
824
825                 for (list<AudioRegion*>::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) {
826
827                         list<AudioRegion*>::iterator tmp;
828
829                         tmp = iter;
830                         ++tmp;
831
832                         if (!canvas_item_visible (rec_rects[n].rectangle)) {
833                                 /* rect already hidden, this region is done */
834                                 iter = tmp;
835                                 continue;
836                         }
837                         
838                         AudioRegion * region = (*iter);
839                         jack_nframes_t origlen = region->length();
840
841                         if (region == rec_regions.back() && rec_active) {
842
843                                 if (last_rec_peak_frame > region->start()) {
844
845                                         jack_nframes_t nlen = last_rec_peak_frame - region->start();
846
847                                         if (nlen != region->length()) {
848
849                                                 region->freeze ();
850                                                 region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this);
851                                                 region->set_length (nlen, this);
852                                                 region->thaw ("updated");
853
854                                                 if (origlen == 1) {
855                                                         /* our special initial length */
856                                                         add_region_view_internal (region, false);
857                                                 }
858
859                                                 /* also update rect */
860                                                 ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle;
861                                                 gdouble xend = _trackview.editor.frame_to_pixel (region->position() + region->length());
862                                                 rect->property_x2() = xend;
863                                         }
864                                 }
865
866                         } else {
867
868                                 jack_nframes_t nlen = _trackview.get_diskstream()->get_captured_frames(n);
869
870                                 if (nlen != region->length()) {
871
872                                         if (region->source(0).length() >= region->start() + nlen) {
873
874                                                 region->freeze ();
875                                                 region->set_position (_trackview.get_diskstream()->get_capture_start_frame(n), this);
876                                                 region->set_length (nlen, this);
877                                                 region->thaw ("updated");
878                                                 
879                                                 if (origlen == 1) {
880                                                         /* our special initial length */
881                                                         add_region_view_internal (region, false);
882                                                 }
883                                                 
884                                                 /* also hide rect */
885                                                 ArdourCanvas::Item * rect = rec_rects[n].rectangle;
886                                                 rect->hide();
887
888                                         }
889                                 }
890                         }
891
892                         iter = tmp;
893                 }
894         }
895 }
896
897 void
898 StreamView::show_all_xfades ()
899 {
900         foreach_crossfadeview (&CrossfadeView::show);
901         crossfades_visible = true;
902 }
903
904 void
905 StreamView::hide_all_xfades ()
906 {
907         foreach_crossfadeview (&CrossfadeView::hide);
908         crossfades_visible = false;
909 }
910
911 void
912 StreamView::hide_xfades_involving (AudioRegionView& rv)
913 {
914         for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
915                 if ((*i)->crossfade.involves (rv.region)) {
916                         (*i)->fake_hide ();
917                 }
918         }
919 }
920
921 void
922 StreamView::reveal_xfades_involving (AudioRegionView& rv)
923 {
924         for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
925                 if ((*i)->crossfade.involves (rv.region) && (*i)->visible()) {
926                         (*i)->show ();
927                 }
928         }
929 }