Fairly major change to the way in which crossfades are handled;
[ardour.git] / gtk2_ardour / audio_streamview.cc
1 /*
2     Copyright (C) 2001, 2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <cmath>
20 #include <cassert>
21 #include <utility>
22
23 #include <gtkmm.h>
24
25 #include <gtkmm2ext/gtk_ui.h>
26
27 #include "pbd/stacktrace.h"
28
29 #include "ardour/audioplaylist.h"
30 #include "ardour/audioregion.h"
31 #include "ardour/audiofilesource.h"
32 #include "ardour/audio_track.h"
33 #include "ardour/source.h"
34 #include "ardour/region_factory.h"
35 #include "ardour/profile.h"
36 #include "ardour/rc_configuration.h"
37 #include "ardour/session.h"
38
39 #include "audio_streamview.h"
40 #include "audio_region_view.h"
41 #include "tape_region_view.h"
42 #include "audio_time_axis.h"
43 #include "canvas-waveview.h"
44 #include "canvas-simplerect.h"
45 #include "region_selection.h"
46 #include "selection.h"
47 #include "public_editor.h"
48 #include "ardour_ui.h"
49 #include "rgb_macros.h"
50 #include "gui_thread.h"
51 #include "utils.h"
52
53 #include "i18n.h"
54
55 using namespace std;
56 using namespace ARDOUR;
57 using namespace PBD;
58 using namespace Editing;
59
60 AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
61         : StreamView (tv)
62 {
63         color_handler ();
64         _amplitude_above_axis = 1.0;
65
66         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&AudioStreamView::parameter_changed, this, _1), gui_context());
67 }
68
69 int
70 AudioStreamView::set_amplitude_above_axis (gdouble app)
71 {
72         RegionViewList::iterator i;
73
74         if (app < 1.0) {
75                 return -1;
76         }
77
78         _amplitude_above_axis = app;
79
80         for (i = region_views.begin(); i != region_views.end(); ++i) {
81                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
82                 if (arv)
83                         arv->set_amplitude_above_axis (app);
84         }
85
86         return 0;
87 }
88
89 RegionView*
90 AudioStreamView::create_region_view (boost::shared_ptr<Region> r, bool wait_for_waves, bool recording)
91 {
92         AudioRegionView *region_view = 0;
93         boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
94
95         if (region == 0) {
96                 return 0;
97         }
98
99         switch (_trackview.audio_track()->mode()) {
100
101         case NonLayered:
102         case Normal:
103                 if (recording) {
104                         region_view = new AudioRegionView (_canvas_group, _trackview, region,
105                                         _samples_per_unit, region_color, recording, TimeAxisViewItem::Visibility(
106                                                         TimeAxisViewItem::ShowFrame |
107                                                         TimeAxisViewItem::HideFrameRight |
108                                                         TimeAxisViewItem::HideFrameLeft |
109                                                         TimeAxisViewItem::HideFrameTB));
110                 } else {
111                         region_view = new AudioRegionView (_canvas_group, _trackview, region,
112                                         _samples_per_unit, region_color);
113                 }
114                 break;
115         case Destructive:
116                 region_view = new TapeAudioRegionView (_canvas_group, _trackview, region,
117                                 _samples_per_unit, region_color);
118                 break;
119         default:
120                 fatal << string_compose (_("programming error: %1"), "illegal track mode in ::add_region_view_internal") << endmsg;
121                 /*NOTREACHED*/
122
123         }
124
125         region_view->init (region_color, wait_for_waves);
126         region_view->set_amplitude_above_axis(_amplitude_above_axis);
127         region_view->set_height (child_height ());
128
129         /* if its the special single-sample length that we use for rec-regions, make it
130            insensitive to events
131         */
132
133         if (region->length() == 1) {
134                 region_view->set_sensitive (false);
135         }
136
137         region_view->set_waveform_scale (Config->get_waveform_scale ());
138         region_view->set_waveform_shape (Config->get_waveform_shape ());
139         region_view->set_waveform_visible (Config->get_show_waveforms ());
140
141         return region_view;
142 }
143
144 RegionView*
145 AudioStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wait_for_waves, bool recording)
146 {
147         RegionView *region_view = create_region_view (r, wait_for_waves, recording);
148
149         if (region_view == 0) {
150                 return 0;
151         }
152
153 //      if(!recording){
154 //              for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
155 //                      if ((*i)->region() == r) {
156 //                              cerr << "audio_streamview in add_region_view_internal region found" << endl;
157                                 /* great. we already have a AudioRegionView for this Region. use it again. */
158
159 //                              (*i)->set_valid (true);
160
161                                 // this might not be necessary
162 //                              AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
163
164 //                              if (arv) {
165 //                                      arv->set_waveform_scale (_waveform_scale);
166 //                                      arv->set_waveform_shape (_waveform_shape);
167 //                              }
168
169 //                              return NULL;
170 //                      }
171 //              }
172 //      }
173
174         region_views.push_front (region_view);
175
176         if (_trackview.editor().internal_editing()) {
177                 region_view->hide_rect ();
178         } else {
179                 region_view->show_rect ();
180         }
181
182         /* catch region going away */
183
184         r->DropReferences.connect (*this, invalidator (*this), boost::bind (&AudioStreamView::remove_region_view, this, boost::weak_ptr<Region> (r)), gui_context());
185
186         RegionViewAdded (region_view);
187
188         return region_view;
189 }
190
191 void
192 AudioStreamView::redisplay_track ()
193 {
194         list<RegionView *>::iterator i;
195
196         // Flag region views as invalid and disable drawing
197         for (i = region_views.begin(); i != region_views.end(); ++i) {
198                 (*i)->set_valid (false);
199                 (*i)->enable_display (false);
200         }
201
202         // Add and display views, and flag them as valid
203         if (_trackview.is_audio_track()) {
204                 _trackview.track()->playlist()->foreach_region(
205                         sigc::hide_return (sigc::mem_fun (*this, &StreamView::add_region_view))
206                         );
207         }
208
209         // Stack regions by layer, and remove invalid regions
210         layer_regions();
211 }
212
213 void
214 AudioStreamView::set_show_waveforms (bool yn)
215 {
216         for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
217                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
218                 if (arv) {
219                         arv->set_waveform_visible (yn);
220                 }
221         }
222 }
223
224 void
225 AudioStreamView::set_waveform_shape (WaveformShape shape)
226 {
227         for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
228                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
229                 if (arv)
230                         arv->set_waveform_shape (shape);
231         }
232 }
233
234 void
235 AudioStreamView::set_waveform_scale (WaveformScale scale)
236 {
237         for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
238                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
239                 if (arv) {
240                         arv->set_waveform_scale (scale);
241                 }
242         }
243 }
244
245 void
246 AudioStreamView::setup_rec_box ()
247 {
248         //cerr << _trackview.name() << " streamview SRB region_views.size() = " << region_views.size() << endl;
249
250         if (_trackview.session()->transport_rolling()) {
251
252                 // cerr << "\trolling\n";
253
254                 if (!rec_active &&
255                     _trackview.session()->record_status() == Session::Recording &&
256                     _trackview.track()->record_enabled()) {
257                         if (_trackview.audio_track()->mode() == Normal && Config->get_show_waveforms_while_recording() && rec_regions.size() == rec_rects.size()) {
258
259                                 /* add a new region, but don't bother if they set show-waveforms-while-recording mid-record */
260
261                                 SourceList sources;
262
263                                 rec_data_ready_connections.drop_connections ();
264                                 boost::shared_ptr<AudioTrack> tr = _trackview.audio_track();
265
266                                 for (uint32_t n = 0; n < tr->n_channels().n_audio(); ++n) {
267                                         boost::shared_ptr<AudioFileSource> src = tr->write_source (n);
268                                         if (src) {
269                                                 sources.push_back (src);
270                                                 src->PeakRangeReady.connect (rec_data_ready_connections,
271                                                                              invalidator (*this),
272                                                                              ui_bind (&AudioStreamView::rec_peak_range_ready, this, _1, _2, boost::weak_ptr<Source>(src)),
273                                                                              gui_context());
274                                         }
275                                 }
276
277                                 // handle multi
278
279                                 framepos_t start = 0;
280                                 if (rec_regions.size() > 0) {
281                                         start = rec_regions.back().first->start()
282                                                         + _trackview.track()->get_captured_frames(rec_regions.size()-1);
283                                 }
284
285                                 PropertyList plist;
286
287                                 plist.add (Properties::start, start);
288                                 plist.add (Properties::length, 1);
289                                 plist.add (Properties::name, string());
290                                 plist.add (Properties::layer, 0);
291
292                                 boost::shared_ptr<AudioRegion> region (
293                                         boost::dynamic_pointer_cast<AudioRegion>(RegionFactory::create (sources, plist, false)));
294
295                                 assert(region);
296                                 region->set_position (_trackview.session()->transport_frame());
297                                 rec_regions.push_back (make_pair(region, (RegionView*) 0));
298                         }
299
300                         /* start a new rec box */
301
302                         boost::shared_ptr<AudioTrack> at;
303
304                         at = _trackview.audio_track(); /* we know what it is already */
305                         framepos_t const frame_pos = at->current_capture_start ();
306                         gdouble xstart = _trackview.editor().frame_to_pixel (frame_pos);
307                         gdouble xend;
308                         uint32_t fill_color;
309
310                         switch (_trackview.audio_track()->mode()) {
311                         case Normal:
312                         case NonLayered:
313                                 xend = xstart;
314                                 fill_color = ARDOUR_UI::config()->canvasvar_RecordingRect.get();
315                                 break;
316
317                         case Destructive:
318                                 xend = xstart + 2;
319                                 fill_color = ARDOUR_UI::config()->canvasvar_RecordingRect.get();
320                                 /* make the recording rect translucent to allow
321                                    the user to see the peak data coming in, etc.
322                                 */
323                                 fill_color = UINT_RGBA_CHANGE_A (fill_color, 120);
324                                 break;
325                         }
326
327                         ArdourCanvas::SimpleRect * rec_rect = new Gnome::Canvas::SimpleRect (*_canvas_group);
328                         rec_rect->property_x1() = xstart;
329                         rec_rect->property_y1() = 1.0;
330                         rec_rect->property_x2() = xend;
331                         rec_rect->property_y2() = child_height ();
332                         rec_rect->property_outline_what() = 0x0;
333                         rec_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_TimeAxisFrame.get();
334                         rec_rect->property_fill_color_rgba() = fill_color;
335                         rec_rect->lower_to_bottom();
336
337                         RecBoxInfo recbox;
338                         recbox.rectangle = rec_rect;
339                         recbox.start = _trackview.session()->transport_frame();
340                         recbox.length = 0;
341
342                         rec_rects.push_back (recbox);
343
344                         screen_update_connection.disconnect();
345                         screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
346                                         sigc::mem_fun (*this, &AudioStreamView::update_rec_box));
347                         rec_updating = true;
348                         rec_active = true;
349
350                 } else if (rec_active &&
351                            (_trackview.session()->record_status() != Session::Recording ||
352                             !_trackview.track()->record_enabled())) {
353                         screen_update_connection.disconnect();
354                         rec_active = false;
355                         rec_updating = false;
356                 }
357
358         } else {
359
360                 // cerr << "\tNOT rolling, rec_rects = " << rec_rects.size() << " rec_regions = " << rec_regions.size() << endl;
361
362                 if (!rec_rects.empty() || !rec_regions.empty()) {
363
364                         /* disconnect rapid update */
365                         screen_update_connection.disconnect();
366                         rec_data_ready_connections.drop_connections ();
367                         rec_updating = false;
368                         rec_active = false;
369
370                         /* remove temp regions */
371
372                         for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); iter != rec_regions.end(); ) {
373                                 list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator tmp;
374
375                                 tmp = iter;
376                                 ++tmp;
377
378                                 (*iter).first->drop_references ();
379
380                                 iter = tmp;
381                         }
382
383                         rec_regions.clear();
384
385                         // cerr << "\tclear " << rec_rects.size() << " rec rects\n";
386
387                         /* transport stopped, clear boxes */
388                         for (vector<RecBoxInfo>::iterator iter=rec_rects.begin(); iter != rec_rects.end(); ++iter) {
389                                 RecBoxInfo &rect = (*iter);
390                                 delete rect.rectangle;
391                         }
392
393                         rec_rects.clear();
394
395                 }
396         }
397 }
398
399 void
400 AudioStreamView::rec_peak_range_ready (framepos_t start, framecnt_t cnt, boost::weak_ptr<Source> weak_src)
401 {
402         ENSURE_GUI_THREAD (*this, &AudioStreamView::rec_peak_range_ready, start, cnt, weak_src)
403
404         boost::shared_ptr<Source> src (weak_src.lock());
405
406         if (!src) {
407                 return;
408         }
409
410         // this is called from the peak building thread
411
412         if (rec_data_ready_map.size() == 0 || start + cnt > last_rec_data_frame) {
413                 last_rec_data_frame = start + cnt;
414         }
415
416         rec_data_ready_map[src] = true;
417
418         if (rec_data_ready_map.size() == _trackview.track()->n_channels().n_audio()) {
419                 update_rec_regions (start, cnt);
420                 rec_data_ready_map.clear();
421         }
422 }
423
424 void
425 AudioStreamView::update_rec_regions (framepos_t start, framecnt_t cnt)
426 {
427         if (!Config->get_show_waveforms_while_recording ()) {
428                 return;
429         }
430
431         uint32_t n = 0;
432
433         for (list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator iter = rec_regions.begin(); iter != rec_regions.end(); n++) {
434
435                 list<pair<boost::shared_ptr<Region>,RegionView*> >::iterator tmp = iter;
436                 ++tmp;
437
438                 assert (n < rec_rects.size());
439
440                 if (!canvas_item_visible (rec_rects[n].rectangle)) {
441                         /* rect already hidden, this region is done */
442                         iter = tmp;
443                         continue;
444                 }
445
446                 boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion>(iter->first);
447
448                 if (!region) {
449                         iter = tmp;
450                         continue;
451                 }
452
453                 framecnt_t origlen = region->length();
454
455                 if (region == rec_regions.back().first && rec_active) {
456
457                         if (last_rec_data_frame > region->start()) {
458
459                                 framecnt_t nlen = last_rec_data_frame - region->start();
460
461                                 if (nlen != region->length()) {
462
463                                         region->suspend_property_changes ();
464                                         region->set_position (_trackview.track()->get_capture_start_frame(n));
465                                         region->set_length (nlen);
466                                         region->resume_property_changes ();
467
468                                         if (origlen == 1) {
469                                                 /* our special initial length */
470                                                 add_region_view_internal (region, false, true);
471                                                 setup_new_rec_layer_time (region);
472                                         }
473
474                                         check_record_layers (region, (region->position() - region->start() + start + cnt));
475
476                                         /* also update rect */
477                                         ArdourCanvas::SimpleRect * rect = rec_rects[n].rectangle;
478                                         gdouble xend = _trackview.editor().frame_to_pixel (region->position() + region->length());
479                                         rect->property_x2() = xend;
480                                 }
481
482                         } else {
483
484                                 framecnt_t nlen = _trackview.track()->get_captured_frames(n);
485
486                                 if (nlen != region->length()) {
487
488                                         if (region->source_length(0) >= region->start() + nlen) {
489
490                                                 region->suspend_property_changes ();
491                                                 region->set_position (_trackview.track()->get_capture_start_frame(n));
492                                                 region->set_length (nlen);
493                                                 region->resume_property_changes ();
494
495                                                 if (origlen == 1) {
496                                                         /* our special initial length */
497                                                         add_region_view_internal (region, false, true);
498                                                 }
499
500                                                 /* also hide rect */
501                                                 ArdourCanvas::Item * rect = rec_rects[n].rectangle;
502                                                 rect->hide();
503
504                                         }
505                                 }
506                         }
507                 }
508
509                 iter = tmp;
510         }
511 }
512
513 void
514 AudioStreamView::show_all_fades ()
515 {
516         for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
517                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
518                 if (arv) {
519                         arv->set_fade_visibility (true);
520                 }
521         }
522 }
523
524 void
525 AudioStreamView::hide_all_fades ()
526 {
527         for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
528                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
529                 if (arv) {
530                         arv->set_fade_visibility (false);
531                 }
532         }
533 }
534
535 void
536 AudioStreamView::color_handler ()
537 {
538         //case cAudioTrackBase:
539         if (_trackview.is_track()) {
540                 canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AudioTrackBase.get();
541         }
542
543         //case cAudioBusBase:
544         if (!_trackview.is_track()) {
545                 if (Profile->get_sae() && _trackview.route()->is_master()) {
546                         canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AudioMasterBusBase.get();
547                 } else {
548                         canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_AudioBusBase.get();
549                 }
550         }
551 }
552
553 void
554 AudioStreamView::parameter_changed (string const & p)
555 {
556         if (p == "show-waveforms") {
557                 set_show_waveforms (Config->get_show_waveforms ());
558         } else if (p == "waveform-scale") {
559                 set_waveform_scale (Config->get_waveform_scale ());
560         } else if (p == "waveform-shape") {
561                 set_waveform_shape (Config->get_waveform_shape ());
562         }
563 }
564