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