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