speed applied to trackcanvas picons/waves, update features5/shortcuts
[goodguy/history.git] / cinelerra-5.1 / cinelerra / resourcepixmap.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22
23
24 #include "arender.h"
25 #include "aedit.h"
26 #include "asset.h"
27 #include "asset.inc"
28 #include "automation.h"
29 #include "autos.h"
30 #include "bcsignals.h"
31 #include "cache.h"
32 #include "clip.h"
33 #include "bccmodels.h"
34 #include "datatype.h"
35 #include "edit.h"
36 #include "edits.h"
37 #include "edl.h"
38 #include "edlsession.h"
39 #include "file.h"
40 #include "filesystem.h"
41 #include "floatauto.h"
42 #include "floatautos.h"
43 #include "framecache.h"
44 #include "indexfile.h"
45 #include "language.h"
46 #include "localsession.h"
47 #include "mwindow.h"
48 #include "mwindowgui.h"
49 #include "renderengine.h"
50 #include "resourcethread.h"
51 #include "resourcepixmap.h"
52 #include "samples.h"
53 #include "theme.h"
54 #include "timelinepane.h"
55 #include "track.h"
56 #include "trackcanvas.h"
57 #include "transportque.h"
58 #include "vedit.h"
59 #include "vframe.h"
60 #include "wavecache.h"
61
62
63 ResourcePixmap::ResourcePixmap(MWindow *mwindow,
64         MWindowGUI *gui,
65         Edit *edit,
66         int pane_number,
67         int w,
68         int h)
69  : BC_Pixmap(gui, w, h)
70 {
71         reset();
72
73         this->mwindow = mwindow;
74         this->gui = gui;
75         this->pane_number = pane_number;
76         startsource = edit->startsource;
77         data_type = edit->track->data_type;
78         if( edit->asset ) {
79                 source_framerate = edit->asset->frame_rate;
80                 source_samplerate = edit->asset->sample_rate;
81         }
82         else
83         if( edit->nested_edl ) {
84                 source_framerate = edit->nested_edl->session->frame_rate;
85                 source_samplerate = edit->nested_edl->session->sample_rate;
86         }
87
88         project_framerate = edit->edl->session->frame_rate;
89         project_samplerate = edit->edl->session->sample_rate;
90         edit_id = edit->id;  pixmap_w = w;  pixmap_h = h;
91 }
92
93 ResourcePixmap::~ResourcePixmap()
94 {
95 }
96
97
98 void ResourcePixmap::reset()
99 {
100         edit_x = 0;
101         pixmap_x = 0;
102         pixmap_w = 0;
103         pixmap_h = 0;
104         zoom_sample = 0;
105         zoom_track = 0;
106         zoom_y = 0;
107         visible = 1;
108 }
109
110 void ResourcePixmap::resize(int w, int h)
111 {
112         int new_w = (w > get_w()) ? w : get_w();
113         int new_h = (h > get_h()) ? h : get_h();
114
115         BC_Pixmap::resize(new_w, new_h);
116 }
117
118
119 void ResourcePixmap::draw_data(TrackCanvas *canvas,
120         Edit *edit,
121         int64_t edit_x,
122         int64_t edit_w,
123         int64_t pixmap_x,
124         int64_t pixmap_w,
125         int64_t pixmap_h,
126         int mode,
127         int indexes_only)
128 {
129 // Get new areas to fill in relative to pixmap
130 // Area to redraw relative to pixmap
131         int refresh_x = 0;
132         int refresh_w = 0;
133
134 // Ignore if called by resourcethread.
135 //      if( mode == IGNORE_THREAD ) return;
136
137         int y = 0;
138         if( mwindow->edl->session->show_titles )
139                 y += mwindow->theme->get_image("title_bg_data")->get_h();
140         Track *track = edit->edits->track;
141
142
143 // If want indexes only & index can't be drawn, don't do anything.
144         int need_redraw = 0;
145         int64_t index_zoom = 0;
146         Indexable *indexable = 0;
147         if( edit->asset ) indexable = edit->asset;
148         if( edit->nested_edl ) indexable = edit->nested_edl;
149         if( indexable && indexes_only ) {
150                 IndexFile indexfile(mwindow, indexable);
151                 if( !indexfile.open_index() ) {
152                         index_zoom = indexable->index_state->index_zoom;
153                         indexfile.close_index();
154                 }
155
156                 if( index_zoom ) {
157                         if( data_type == TRACK_AUDIO ) {
158                                 double asset_over_session = (double)indexable->get_sample_rate() /
159                                         mwindow->edl->session->sample_rate;
160                                 if( index_zoom <= mwindow->edl->local_session->zoom_sample *
161                                         asset_over_session )
162                                         need_redraw = 1;
163                         }
164                 }
165
166                 if( !need_redraw )
167                         return;
168         }
169
170
171 // Redraw everything
172 /* Incremental drawing is not possible with resource thread */
173         if( 1 )
174 //              edit->startsource != this->startsource ||
175 //              mwindow->edl->session->sample_rate != project_samplerate ||
176 //              !EQUIV(mwindow->edl->session->frame_rate, project_framerate) ||
177 //              mwindow->edl->local_session->zoom_sample != zoom_sample ||
178 //              mwindow->edl->local_session->zoom_track != zoom_track ||
179 //              this->pixmap_h != pixmap_h ||
180 //              (data_type == TRACK_AUDIO &&
181 //                      mwindow->edl->local_session->zoom_y != zoom_y) ||
182 //              (mode == 2) ||
183 //              need_redraw)
184         {
185 // Redraw the whole thing.
186                 refresh_x = 0;
187                 refresh_w = pixmap_w;
188         }
189         else {
190 // Start translated right
191                 if( pixmap_w == this->pixmap_w && edit_x < this->edit_x && edit_w != pixmap_w ) {
192                         refresh_w = this->edit_x - edit_x;
193                         refresh_x = this->pixmap_w - refresh_w;
194
195 // Moved completely off the pixmap
196                         if( refresh_w > this->pixmap_w ) {
197                                 refresh_w = this->pixmap_w;
198                                 refresh_x = 0;
199                         }
200                         else {
201                                 copy_area(refresh_w,
202                                         y,
203                                         refresh_x,
204                                         mwindow->edl->local_session->zoom_track,
205                                         0,
206                                         y);
207                         }
208                 }
209                 else
210 // Start translated left
211                 if( pixmap_w == this->pixmap_w && edit_x > this->edit_x && edit_w != pixmap_w ) {
212                         refresh_x = 0;
213                         refresh_w = edit_x - this->edit_x;
214
215 // Moved completely off the pixmap
216                         if( refresh_w > this->pixmap_w ) {
217                                 refresh_w = this->pixmap_w;
218                         }
219                         else {
220                                 copy_area(0,
221                                         y,
222                                         this->pixmap_w - refresh_w,
223                                         mwindow->edl->local_session->zoom_track,
224                                         refresh_w,
225                                         y);
226                         }
227                 }
228                 else
229 // Start translated right and pixmap came off of right side
230                 if( pixmap_w < this->pixmap_w && edit_x < this->edit_x &&
231                         this->edit_x + edit_w > this->pixmap_x + this->pixmap_w ) {
232                         refresh_w = (this->edit_x + edit_w) - (this->pixmap_x + this->pixmap_w);
233                         refresh_x = pixmap_w - refresh_w;
234
235                         if( refresh_w >= pixmap_w ) {
236                                 refresh_x = 0;
237                                 refresh_w = pixmap_w;
238                         }
239                         else {
240                                 copy_area(this->edit_x - edit_x,
241                                         y,
242                                         pixmap_w - refresh_w,
243                                         mwindow->edl->local_session->zoom_track,
244                                         0,
245                                         y);
246                         }
247                 }
248                 else
249 // Start translated right and reduced in size on the right.
250                 if( pixmap_w < this->pixmap_w && edit_x < this->edit_x ) {
251                         refresh_x = 0;
252                         refresh_w = 0;
253
254                         copy_area(this->pixmap_w - pixmap_w,
255                                 y,
256                                 pixmap_w,
257                                 mwindow->edl->local_session->zoom_track,
258                                 0,
259                                 y);
260                 }
261                 else
262 // Start translated left and pixmap came off left side
263                 if( edit_x >= 0 && this->edit_x < 0 ) {
264                         refresh_x = 0;
265                         refresh_w = -this->edit_x;
266
267                         if( refresh_w > pixmap_w ) {
268                                 refresh_w = pixmap_w;
269                         }
270                         else {
271                                 copy_area(0,
272                                                 y,
273                                                 this->pixmap_w,
274                                                 mwindow->edl->local_session->zoom_track,
275                                                 refresh_w,
276                                                 y);
277                         }
278                 }
279                 else
280 // Start translated left and reduced in size on the right
281                 if( pixmap_w < this->pixmap_w && edit_x > this->edit_x ) {
282                         refresh_x = 0;
283                         refresh_w = 0;
284                 }
285                 else
286 // Start translated right and left went into left side.
287                 if( pixmap_w > this->pixmap_w && edit_x < 0 && this->edit_x > 0 ) {
288                         refresh_w = pixmap_w - (edit_x + this->pixmap_w);
289                         refresh_x = pixmap_w - refresh_w;
290
291 // Moved completely off new pixmap
292                         if( refresh_w > pixmap_w ) {
293                                 refresh_w = pixmap_w;
294                                 refresh_x = 0;
295                         }
296                         else {
297                                 copy_area(-edit_x,
298                                         y,
299                                         refresh_x,
300                                         mwindow->edl->local_session->zoom_track,
301                                         0,
302                                         y);
303                         }
304                 }
305                 else
306 // Start translated right and increased in size on the right
307                 if( pixmap_w > this->pixmap_w && edit_x <= this->edit_x ) {
308                         refresh_w = pixmap_w - this->pixmap_w;
309                         refresh_x = pixmap_w - refresh_w;
310                 }
311                 else
312 // Start translated left and increased in size on the right
313                 if( pixmap_w > this->pixmap_w && edit_x > this->edit_x ) {
314                         refresh_x = 0;
315                         refresh_w = edit_x - this->edit_x;
316
317 // Moved completely off new pixmap
318                         if( refresh_w > this->pixmap_w ) {
319                                 refresh_w = pixmap_w;
320                                 refresh_x = 0;
321                         }
322 // Shift and insert
323                         else {
324                                 copy_area(0,
325                                         y,
326                                         this->pixmap_w,
327                                         mwindow->edl->local_session->zoom_track,
328                                         refresh_w,
329                                         y);
330                         }
331                 }
332         }
333
334 // Update pixmap settings
335         this->edit_id = edit->id;
336         this->startsource = edit->startsource;
337
338         if( edit->asset )
339                 this->source_framerate = edit->asset->frame_rate;
340         else
341         if( edit->nested_edl )
342                 this->source_framerate = edit->nested_edl->session->frame_rate;
343
344         if( edit->asset )
345                 this->source_samplerate = edit->asset->sample_rate;
346         else
347         if( edit->nested_edl )
348                 this->source_samplerate = edit->nested_edl->session->sample_rate;
349
350         this->project_framerate = edit->edl->session->frame_rate;
351         this->project_samplerate = edit->edl->session->sample_rate;
352         this->edit_x = edit_x;
353         this->pixmap_x = pixmap_x;
354         this->pixmap_w = pixmap_w;
355         this->pixmap_h = pixmap_h;
356         this->zoom_sample = mwindow->edl->local_session->zoom_sample;
357         this->zoom_track = mwindow->edl->local_session->zoom_track;
358         this->zoom_y = mwindow->edl->local_session->zoom_y;
359
360
361
362 // Draw background image
363         if( refresh_w > 0 )
364                 mwindow->theme->draw_resource_bg(canvas,
365                         this,
366                         edit_x,
367                         edit_w,
368                         pixmap_x,
369                         refresh_x,
370                         y,
371                         refresh_x + refresh_w,
372                         mwindow->edl->local_session->zoom_track + y);
373 //printf("ResourcePixmap::draw_data 70\n");
374
375
376 // Draw media which already exists
377         if( track->draw ) {
378                 switch( track->data_type )
379                 {
380                         case TRACK_AUDIO:
381                                 draw_audio_resource(canvas,
382                                         edit,
383                                         refresh_x,
384                                         refresh_w);
385                                 break;
386
387                         case TRACK_VIDEO:
388                                 draw_video_resource(canvas,
389                                         edit,
390                                         edit_x,
391                                         edit_w,
392                                         pixmap_x,
393                                         pixmap_w,
394                                         refresh_x,
395                                         refresh_w,
396                                         mode);
397                                 break;
398
399                         case TRACK_SUBTITLE:
400                                 draw_subttl_resource(canvas,
401                                         edit,
402                                         refresh_x,
403                                         refresh_w);
404                                 break;
405                 }
406         }
407
408 // Draw title
409 SET_TRACE
410         if( mwindow->edl->session->show_titles )
411                 draw_title(canvas,
412                         edit,
413                         edit_x,
414                         edit_w,
415                         pixmap_x,
416                         pixmap_w);
417 SET_TRACE
418 }
419
420 void ResourcePixmap::draw_title(TrackCanvas *canvas,
421         Edit *edit, int64_t edit_x, int64_t edit_w,
422         int64_t pixmap_x, int64_t pixmap_w)
423 {
424 // coords relative to pixmap
425         int64_t total_x = edit_x - pixmap_x, total_w = edit_w;
426         int64_t x = total_x, w = total_w;
427         int left_margin = 10;
428
429         if( x < 0 ) { w -= -x; x = 0; }
430         if( w > pixmap_w ) w -= w - pixmap_w;
431
432         canvas->draw_3segmenth(x, 0, w, total_x, total_w,
433                 mwindow->theme->get_image("title_bg_data"), this);
434
435 //      if( total_x > -BC_INFINITY ) {
436                 char title[BCTEXTLEN];
437                 char channel[BCTEXTLEN];
438                 title[0] = 0;
439                 channel[0] = 0;
440                 FileSystem fs;
441
442                 if( edit->user_title[0] )
443                         strcpy(title, edit->user_title);
444                 else if( edit->nested_edl ) {
445 //printf("ResourcePixmap::draw_title %s\n", edit->nested_edl->project_path);
446                         fs.extract_name(title, edit->nested_edl->path);
447
448 // EDLs only have 1 video output
449                         if( edit->track->data_type == TRACK_AUDIO ) {
450                                 sprintf(channel, " #%d", edit->channel + 1);
451                                 strcat(title, channel);
452                         }
453                 }
454                 else if( edit->asset ) {
455                         fs.extract_name(title, edit->asset->path);
456                         sprintf(channel, " #%d", edit->channel + 1);
457                         strcat(title, channel);
458                 }
459
460                 canvas->set_color(mwindow->theme->title_color);
461                 canvas->set_font(mwindow->theme->title_font);
462
463 // Justify the text on the left boundary of the edit if it is visible.
464 // Otherwise justify it on the left side of the screen.
465                 int text_x = total_x + left_margin;
466                 text_x = MAX(left_margin, text_x);
467 //printf("ResourcePixmap::draw_title 1 %d\n", text_x);
468                 canvas->draw_text(text_x,
469                         canvas->get_text_ascent(mwindow->theme->title_font) + 2,
470                         title, strlen(title), this);
471 //      }
472 }
473
474
475 // Need to draw one more x
476 void ResourcePixmap::draw_audio_resource(TrackCanvas *canvas, Edit *edit, int x, int w)
477 {
478         if( w <= 0 ) return;
479         if( !edit->asset && !edit->nested_edl ) return;
480         Indexable *indexable = 0;
481         if( edit->asset ) indexable = edit->asset;
482         if( edit->nested_edl ) indexable = edit->nested_edl;
483 // printf("ResourcePixmap::draw_audio_resource %d x=%d w=%d\n", __LINE__, x, w);
484 SET_TRACE
485
486         IndexState *index_state = indexable->index_state;
487         double asset_over_session = (double)indexable->get_sample_rate() /
488                 mwindow->edl->session->sample_rate;
489
490 // Develop strategy for drawing
491 // printf("ResourcePixmap::draw_audio_resource %d %p %d\n",
492 // __LINE__,
493 // index_state,
494 // index_state->index_status);
495         switch( index_state->index_status )
496         {
497                 case INDEX_NOTTESTED:
498                         return;
499                         break;
500 // Disabled.  All files have an index.
501 //              case INDEX_TOOSMALL:
502 //                      draw_audio_source(canvas, edit, x, w);
503 //                      break;
504                 case INDEX_BUILDING:
505                 case INDEX_READY:
506                 {
507                         IndexFile indexfile(mwindow, indexable);
508                         if( !indexfile.open_index() ) {
509                                 if( index_state->index_zoom >
510                                                 mwindow->edl->local_session->zoom_sample *
511                                                 asset_over_session ) {
512 //printf("ResourcePixmap::draw_audio_resource %d\n", __LINE__);
513
514                                         draw_audio_source(canvas, edit, x, w);
515                                 }
516                                 else {
517 //printf("ResourcePixmap::draw_audio_resource %d\n", __LINE__);
518                                         indexfile.draw_index(canvas,
519                                                 this,
520                                                 edit,
521                                                 x,
522                                                 w);
523 SET_TRACE
524                                 }
525
526                                 indexfile.close_index();
527 SET_TRACE
528                         }
529                         break;
530                 }
531         }
532 }
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551 void ResourcePixmap::draw_audio_source(TrackCanvas *canvas,
552         Edit *edit,
553         int x,
554         int w)
555 {
556         w++;
557         Indexable *indexable = edit->get_source();
558         FloatAutos *speed_autos = (FloatAutos *)edit->track->automation->autos[AUTOMATION_SPEED];
559         double asset_over_session = (double)indexable->get_sample_rate() /
560                 mwindow->edl->session->sample_rate;
561         int center_pixel = mwindow->edl->local_session->zoom_track / 2;
562         if( mwindow->edl->session->show_titles )
563                 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
564         int64_t scale_y = mwindow->edl->local_session->zoom_y;
565         int y_max = center_pixel + scale_y / 2 - 1;
566
567         int64_t start_source = (pixmap_x - edit_x + x) *
568                 mwindow->edl->local_session->zoom_sample + edit->startsource;
569         int64_t start_speed = speed_autos->automation_integral(0, start_source, PLAY_FORWARD);
570         int64_t start_asset = start_speed * asset_over_session;
571         if( start_asset < 0 ) start_asset = 0;
572         int64_t end_source = (pixmap_x - edit_x + x + w) *
573                 mwindow->edl->local_session->zoom_sample + edit->startsource;
574         int64_t end_speed = speed_autos->automation_integral(0, end_source, PLAY_FORWARD);
575         int64_t end_asset = end_speed * asset_over_session;
576         if( end_asset < 0 ) end_asset = 0;
577         int64_t total_source_samples = end_asset - start_asset;
578         if( total_source_samples < 0 ) total_source_samples = 0;
579
580 // Single sample zoom
581         if( mwindow->edl->local_session->zoom_sample == 1 ) {
582                 Samples *buffer = new Samples(total_source_samples);
583                 int result = 0;
584                 canvas->set_color(mwindow->theme->audio_color);
585
586                 if( indexable->is_asset ) {
587                         mwindow->gui->unlock_window();
588                         File *source = mwindow->audio_cache->check_out(edit->asset, mwindow->edl);
589                         mwindow->gui->lock_window("draw_audio_source");
590
591                         if( !source ) {
592                                 printf(_("ResourcePixmap::draw_audio_source: failed to check out %s for drawing.\n"), edit->asset->path);
593                                 return;
594                         }
595
596                         source->set_audio_position(start_speed);
597                         source->set_channel(edit->channel);
598                         result = source->read_samples(buffer, total_source_samples);
599                         mwindow->audio_cache->check_in(edit->asset);
600                 }
601                 else {
602                         if( mwindow->gui->render_engine &&
603                                 mwindow->gui->render_engine_id != indexable->id ) {
604                                 delete mwindow->gui->render_engine;
605                                 mwindow->gui->render_engine = 0;
606                         }
607
608                         if( !mwindow->gui->render_engine ) {
609                                 TransportCommand command;
610                                 command.command = NORMAL_FWD;
611                                 command.get_edl()->copy_all(edit->nested_edl);
612                                 command.change_type = CHANGE_ALL;
613                                 command.realtime = 0;
614                                 mwindow->gui->render_engine = new RenderEngine(0,
615                                         mwindow->preferences, 0, 0);
616                                 mwindow->gui->render_engine_id = edit->nested_edl->id;
617                                 mwindow->gui->render_engine->set_acache(mwindow->audio_cache);
618                                 mwindow->gui->render_engine->arm_command(&command);
619                         }
620
621                         Samples *temp_buffer[MAX_CHANNELS];
622                         bzero(temp_buffer, MAX_CHANNELS * sizeof(double*));
623                         for( int i = 0; i < indexable->get_audio_channels(); i++ ) {
624                                 temp_buffer[i] = new Samples(total_source_samples);
625                         }
626
627                         if( mwindow->gui->render_engine->arender ) {
628                                 mwindow->gui->render_engine->arender->process_buffer(
629                                         temp_buffer, total_source_samples, start_speed);
630                                 memcpy(buffer->get_data(),
631                                         temp_buffer[edit->channel]->get_data(),
632                                         total_source_samples * sizeof(double));
633                         }
634
635                         for( int i = 0; i < indexable->get_audio_channels(); i++ ) {
636                                 delete temp_buffer[i];
637                         }
638                 }
639
640                 if( !result ) {
641                         double *samples = buffer->get_data();
642                         int y1 = center_pixel - samples[0] * scale_y / 2;
643                         int y2 = CLIP(y1, 0, y_max);
644
645                         for( int x0=0; x0<w; ++x0 ) {
646                                 int x1 = x0 + x, x2 = x1 + 1;
647                                 int64_t pos_project = (pixmap_x - edit_x + x2) *
648                                         mwindow->edl->local_session->zoom_sample + edit->startsource;
649                                 int64_t pos_speed = speed_autos->automation_integral(0, pos_project, PLAY_FORWARD);
650                                 int j = (pos_speed - start_speed) * asset_over_session;
651                                 CLAMP(j, 0, total_source_samples);
652                                 int y0 = y2;
653                                 y1 = center_pixel - samples[j] * scale_y / 2;
654                                 y2 = CLIP(y1, 0, y_max);
655 //printf("ResourcePixmap::draw_audio_source %d %d %d\n", __LINE__, y1, y2);
656                                 canvas->draw_line(x0, y0, x2, y2, this);
657                         }
658                 }
659
660                 delete buffer;
661         }
662         else {
663 // Multiple sample zoom
664                 int first_pixel = 1;
665                 int prev_y1 = -1;
666                 int prev_y2 = y_max;
667                 int x2 = x + w;
668
669                 canvas->set_color(mwindow->theme->audio_color);
670
671                 int64_t next_project = (pixmap_x - edit_x + x) *
672                         mwindow->edl->local_session->zoom_sample + edit->startsource;
673                 int64_t next_speed = speed_autos->automation_integral(0, next_project, PLAY_FORWARD);
674                 int64_t next_asset = next_speed * asset_over_session;
675
676 // Draw each pixel from the cache
677 //printf("ResourcePixmap::draw_audio_source %d x=%d w=%d\n", __LINE__, x, w);
678                 while( x < x2 ) {
679                         int64_t prev_asset = next_asset;
680                         next_project = (pixmap_x - edit_x + x) *
681                                 mwindow->edl->local_session->zoom_sample + edit->startsource;
682                         next_speed = speed_autos->automation_integral(0, next_project, PLAY_FORWARD);
683                         next_asset = next_speed * asset_over_session;
684 // Starting sample of pixel relative to asset rate.
685                         WaveCacheItem *item = mwindow->wave_cache->get_wave(indexable->id,
686                                         edit->channel, prev_asset, next_asset);
687                         if( item ) {
688 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
689                                 int y_lo = (int)(center_pixel - item->low * scale_y / 2);
690                                 int y1 = CLIP(y_lo, 0, y_max);
691                                 int y_hi = (int)(center_pixel - item->high * scale_y / 2);
692                                 int y2 = CLIP(y_hi, 0, y_max);
693
694                                 if( !first_pixel ) {
695                                         y_lo = MIN(y1,prev_y2);
696                                         y_hi = MAX(y2,prev_y1);
697                                 }
698                                 else {
699                                         first_pixel = 0;
700                                         y_lo = y1;
701                                         y_hi = y2;
702                                 }
703                                 prev_y1 = y1;  prev_y2 = y2;
704                                 canvas->draw_line(x, y_lo, x, y_hi, this);
705 //printf("ResourcePixmap::draw_audio_source %d %d %d %d\n", __LINE__, x, y1, y2);
706                                 mwindow->wave_cache->unlock();
707                         }
708                         else {
709 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
710                                 gui->resource_thread->add_wave(this,
711                                         canvas->pane->number, indexable, x,
712                                         edit->channel, prev_asset, next_asset);
713                                 first_pixel = 1;
714                                 prev_y1 = -1;
715                                 prev_y2 = y_max;
716                         }
717                         ++x;
718                 }
719         }
720         canvas->test_timer();
721 }
722
723 void ResourcePixmap::draw_wave(TrackCanvas *canvas, int x, double high, double low)
724 {
725         int top_pixel = 0;
726         if( mwindow->edl->session->show_titles )
727                 top_pixel = mwindow->theme->get_image("title_bg_data")->get_h();
728         int center_pixel = mwindow->edl->local_session->zoom_track / 2 + top_pixel;
729         int bottom_pixel = top_pixel + mwindow->edl->local_session->zoom_track;
730         int y1 = (int)(center_pixel -
731                 low * mwindow->edl->local_session->zoom_y / 2);
732         int y2 = (int)(center_pixel -
733                 high * mwindow->edl->local_session->zoom_y / 2);
734         CLAMP(y1, top_pixel, bottom_pixel);
735         CLAMP(y2, top_pixel, bottom_pixel);
736         canvas->set_color(mwindow->theme->audio_color);
737         canvas->draw_line(x, y1, x, y2, this);
738 }
739
740
741 void ResourcePixmap::draw_video_resource(TrackCanvas *canvas,
742         Edit *edit, int64_t edit_x, int64_t edit_w, int64_t pixmap_x, int64_t pixmap_w,
743         int refresh_x, int refresh_w, int mode)
744 {
745 //PRINT_TRACE
746 //BC_Signals::dump_stack();
747
748 // pixels spanned by a picon
749         int64_t picon_w = Units::round(edit->picon_w());
750         int64_t picon_h = edit->picon_h();
751 //      if( picon_w <= 0 || picon_w > edit_w ) return;
752 // Don't draw video if picon is empty, or edit only hairline
753         if( picon_w < 1 || edit_w < 2 ) return;
754 // or bigger than edit and fills at less than 1.5 percent timeline
755         if( picon_w > edit_w && edit_w < canvas->get_w()/64 ) return;
756
757 // pixels spanned by a frame
758         double frame_w = edit->frame_w();
759
760 // Frames spanned by a picon
761         double frames_per_picon = edit->frames_per_picon();
762
763 // Current pixel relative to pixmap
764         int x = 0;
765         int y = 0;
766         if( mwindow->edl->session->show_titles )
767                 y += mwindow->theme->get_image("title_bg_data")->get_h();
768 // Frame in project touched by current pixel
769         int64_t project_frame;
770
771 // Get first frame touched by x and fix x to start of frame
772         if( frames_per_picon > 1 ) {
773                 int picon = Units::to_int64(
774                         (double)((int64_t)refresh_x + pixmap_x - edit_x) / picon_w);
775                 x = picon_w * picon + edit_x - pixmap_x;
776                 project_frame = Units::to_int64((double)picon * frames_per_picon);
777         }
778         else {
779                 project_frame = Units::to_int64((double)((int64_t)refresh_x + pixmap_x - edit_x) /
780                         frame_w);
781                 x = Units::round((double)project_frame * frame_w + edit_x - pixmap_x);
782         }
783
784         FloatAutos *speed_autos = (FloatAutos *)edit->track->automation->autos[AUTOMATION_SPEED];
785
786 // Draw only cached frames
787         while( x < refresh_x + refresh_w ) {
788                 int64_t source_frame = project_frame + edit->startsource;
789                 source_frame = speed_autos->automation_integral(0, source_frame, PLAY_FORWARD);
790                 VFrame *picon_frame = 0;
791                 Indexable *indexable = edit->get_source();
792                 int use_cache = 0;
793                 int id = -1;
794
795                 id = indexable->id;
796
797                 if( id >= 0 ) {
798                         picon_frame = mwindow->frame_cache->get_frame_ptr(source_frame, edit->channel,
799                                 mwindow->edl->session->frame_rate, BC_RGB888, picon_w, picon_h, id);
800                 }
801
802                 if( picon_frame != 0 ) {
803                         use_cache = 1;
804                 }
805                 else {
806 // Set picon thread to draw in background
807                         if( mode != IGNORE_THREAD ) {
808 // printf("ResourcePixmap::draw_video_resource %d %d %lld\n",
809 // __LINE__,
810 // mwindow->frame_cache->total(),
811 // source_frame);
812                                 gui->resource_thread->add_picon(this, canvas->pane->number, x, y,
813                                         picon_w, picon_h, mwindow->edl->session->frame_rate,
814                                         source_frame, edit->channel, indexable);
815                         }
816                 }
817
818                 if( picon_frame )
819                         draw_vframe(picon_frame, x, y, picon_w, picon_h, 0, 0);
820
821 // Unlock the get_frame_ptr command
822                 if( use_cache )
823                         mwindow->frame_cache->unlock();
824
825                 if( frames_per_picon > 1 ) {
826                         x += Units::round(picon_w);
827                         project_frame = Units::to_int64(frames_per_picon * (int64_t)((double)(x + pixmap_x - edit_x) / picon_w));
828                 }
829                 else {
830                         x += Units::round(frame_w);
831                         project_frame = (int64_t)((double)(x + pixmap_x - edit_x) / frame_w);
832                 }
833
834
835                 canvas->test_timer();
836         }
837 }
838
839 #include "strack.h"
840
841 void ResourcePixmap::draw_subttl_resource(TrackCanvas *canvas, Edit *edit, int x, int w)
842 {
843         SEdit *sedit = (SEdit *)edit;
844         char *text = sedit->get_text();
845         if( !*text || w < 10 ) return;
846         int center_pixel = mwindow->edl->local_session->zoom_track / 2;
847         if( mwindow->edl->session->show_titles )
848                 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
849         int64_t scale_y = mwindow->edl->local_session->zoom_y;
850         int x0 = edit_x;
851         if( x0 < 0 ) x0 = -x0;
852         int x1 = (int)(pixmap_x - x0 + x);
853         int y_max = center_pixel + scale_y / 2 - 1;
854         int font = MEDIUMFONT, color = WHITE;
855         canvas->set_font(font);
856         canvas->set_color(color);
857         int ch = canvas->get_text_height(font);
858         int hh = canvas->get_text_height(font,text) + ch/2;
859         int y1 = y_max - hh - 10;
860         if( y1 < 0 ) y1 = 0;
861         canvas->draw_text(x1, y1, text, -1, this);
862 }
863
864 void ResourcePixmap::dump()
865 {
866         printf("ResourcePixmap %p\n", this);
867         printf(" edit %jx edit_x %jd pixmap_x %jd pixmap_w %jd visible %d\n",
868                 edit_id, edit_x, pixmap_x, pixmap_w, visible);
869 }
870