improve delays created by vicon drawing locks, reset_cache segv fix, gang track toolt...
[goodguy/cinelerra.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 "preferences.h"
50 #include "renderengine.h"
51 #include "resourcethread.h"
52 #include "resourcepixmap.h"
53 #include "samples.h"
54 #include "theme.h"
55 #include "timelinepane.h"
56 #include "track.h"
57 #include "trackcanvas.h"
58 #include "transportque.h"
59 #include "vedit.h"
60 #include "vframe.h"
61 #include "wavecache.h"
62
63
64 ResourcePixmap::ResourcePixmap(MWindow *mwindow,
65         MWindowGUI *gui,
66         Edit *edit,
67         int pane_number,
68         int w,
69         int h)
70  : BC_Pixmap(gui, w, h)
71 {
72         reset();
73
74         this->mwindow = mwindow;
75         this->gui = gui;
76         this->pane_number = pane_number;
77         startsource = edit->startsource;
78         data_type = edit->track->data_type;
79         if( edit->asset ) {
80                 source_framerate = edit->asset->frame_rate;
81                 source_samplerate = edit->asset->sample_rate;
82         }
83         else
84         if( edit->nested_edl ) {
85                 source_framerate = edit->nested_edl->session->frame_rate;
86                 source_samplerate = edit->nested_edl->session->sample_rate;
87         }
88         data_h = edit->track->data_h;
89         project_framerate = edit->edl->session->frame_rate;
90         project_samplerate = edit->edl->session->sample_rate;
91         edit_id = edit->id;  pixmap_w = w;  pixmap_h = h;
92 }
93
94 ResourcePixmap::~ResourcePixmap()
95 {
96 }
97
98
99 void ResourcePixmap::reset()
100 {
101         edit_x = 0;
102         pixmap_x = 0;
103         pixmap_w = 0;
104         pixmap_h = 0;
105         zoom_sample = 0;
106         visible = 1;
107 }
108
109 void ResourcePixmap::resize(int w, int h)
110 {
111         int new_w = (w > get_w()) ? w : get_w();
112         int new_h = (h > get_h()) ? h : get_h();
113
114         BC_Pixmap::resize(new_w, new_h);
115 }
116
117 void ResourcePixmap::update_settings(Edit *edit,
118         int64_t edit_x, int64_t edit_w,
119         int64_t pixmap_x, int64_t pixmap_w, int64_t pixmap_h)
120 {
121         this->edit_id = edit->id;
122         this->edit_x = edit_x;
123         this->pixmap_x = pixmap_x;
124         this->pixmap_w = pixmap_w;
125         this->pixmap_h = pixmap_h;
126
127         startsource = edit->startsource;
128         if( edit->asset )
129                 source_framerate = edit->asset->frame_rate;
130         else
131         if( edit->nested_edl )
132                 source_framerate = edit->nested_edl->session->frame_rate;
133         if( edit->asset )
134                 source_samplerate = edit->asset->sample_rate;
135         else if( edit->nested_edl )
136                 source_samplerate = edit->nested_edl->session->sample_rate;
137
138         project_framerate = edit->edl->session->frame_rate;
139         project_samplerate = edit->edl->session->sample_rate;
140         zoom_sample = mwindow->edl->local_session->zoom_sample;
141 }
142
143 void ResourcePixmap::draw_data(TrackCanvas *canvas,
144         Edit *edit, int64_t edit_x, int64_t edit_w,
145         int64_t pixmap_x, int64_t pixmap_w, int64_t pixmap_h,
146         int mode, int indexes_only)
147 {
148 // Get new areas to fill in relative to pixmap
149 // Area to redraw relative to pixmap
150         int refresh_x = 0;
151         int refresh_w = 0;
152
153 // Ignore if called by resourcethread.
154         if( mode == IGNORE_THREAD ) return;
155
156         int y = 0;
157         if( edit->track->show_titles() )
158                 y += mwindow->theme->get_image("title_bg_data")->get_h();
159
160 // If want indexes only & index can't be drawn, don't do anything.
161         int need_redraw = 0;
162         int64_t index_zoom = 0;
163         Indexable *indexable = 0;
164         if( edit->asset ) indexable = edit->asset;
165         if( edit->nested_edl ) indexable = edit->nested_edl;
166         if( indexable && indexes_only ) {
167                 IndexFile indexfile(mwindow, indexable);
168                 if( !indexfile.open_index() ) {
169                         index_zoom = indexable->index_state->index_zoom;
170                         indexfile.close_index();
171                 }
172
173                 if( index_zoom ) {
174                         if( data_type == TRACK_AUDIO ) {
175                                 double asset_over_session = (double)indexable->get_sample_rate() /
176                                         mwindow->edl->session->sample_rate;
177                                 if( index_zoom <= mwindow->edl->local_session->zoom_sample *
178                                         asset_over_session )
179                                         need_redraw = 1;
180                         }
181                 }
182
183                 if( !need_redraw )
184                         return;
185         }
186
187 /* Incremental drawing is not possible with resource thread */
188 // Redraw everything
189         refresh_x = 0;
190         refresh_w = pixmap_w;
191         Track *track = edit->track;
192
193 // Draw background image
194         if( refresh_w > 0 ) {
195                 int x1 = refresh_x, x2 = x1 + refresh_w;
196                 int y1 = y, y2 = y1 + track->data_h;
197                 int color = mwindow->get_title_color(edit);
198                 mwindow->theme->draw_resource_bg(canvas, this, color,
199                         edit, edit_x, edit_w, pixmap_x, x1,y1, x2,y2);
200         }
201 //printf("ResourcePixmap::draw_data 70\n");
202
203
204 // Draw media which already exists
205         if( track->draw ) {
206                 switch( track->data_type )
207                 {
208                         case TRACK_AUDIO:
209                                 draw_audio_resource(canvas,
210                                         edit, refresh_x, refresh_w);
211                                 break;
212
213                         case TRACK_VIDEO:
214                                 draw_video_resource(canvas, edit, edit_x, edit_w,
215                                         pixmap_x, pixmap_w, refresh_x, refresh_w,
216                                         mode);
217                                 break;
218
219                         case TRACK_SUBTITLE:
220                                 draw_subttl_resource(canvas, edit,
221                                         refresh_x, refresh_w);
222                                 break;
223                 }
224         }
225 SET_TRACE
226 }
227
228
229 VFrame *ResourcePixmap::change_title_color(VFrame *title_bg, int color)
230 {
231         int colormodel = title_bg->get_color_model();
232         int bpp = BC_CModels::calculate_pixelsize(colormodel);
233         int tw = title_bg->get_w(), tw1 = tw-1, th = title_bg->get_h();
234         VFrame *title_bar = new VFrame(tw, th, colormodel);
235         uint8_t **bar_rows = title_bar->get_rows();
236         const uint8_t gap_grey = 0x4a;
237         union { unsigned rgba; struct { uint8_t r,g,b,a; }; } c;
238         c.r = color>>16;  c.g = color>>8;  c.b = color>>0;  c.a = 0xff;
239         if( BC_CModels::has_alpha(colormodel) && // fast path
240             BC_CModels::calculate_pixelsize(colormodel) == sizeof(unsigned) ) {
241                 const unsigned gap_rgba = (0xff<<24) |
242                         (gap_grey<<16) | (gap_grey<<8) | (gap_grey<<0);
243                 if( th > 0 ) {
244                         unsigned *bp = (unsigned *)bar_rows[0];
245                         for( int i=tw; --i>=0; ) *bp++ = gap_rgba;
246                 }
247                 for( int y=1; y<th; ++y ) {
248                         unsigned *bp = (unsigned *)bar_rows[y];
249                         if( tw > 0 ) *bp++ = gap_rgba;
250                         for( int i=tw1; --i>0; ++bp ) *bp = c.rgba;
251                         if( tw > 1 ) *bp = gap_rgba;
252                 }
253         }
254         else {
255                 if( th > 0 ) {
256                         uint8_t *cp = bar_rows[0];
257                         for( int x=0; x<tw; ++x ) {
258                                 cp[0] = cp[1] = cp[2] = gap_grey;
259                                 if( bpp > 3 ) cp[3] = 0xff;
260                                 cp += bpp;
261                         }
262                 }
263                 for( int y=1; y<th; ++y ) {
264                         uint8_t *cp = bar_rows[y];
265                         if( tw > 0 ) {
266                                 cp[0] = cp[1] = cp[2] = gap_grey;
267                                 if( bpp > 3 ) cp[3] = 0xff;
268                                 cp += bpp;
269                         }
270                         for( int x=1; x<tw1; ++x ) {
271                                 cp[0] = c.r; cp[1] = c.g; cp[2] = c.b;
272                                 if( bpp > 3 ) cp[3] = 0xff;
273                                 cp += bpp;
274                         }
275                         if( tw > 1 ) {
276                                 cp[0] = cp[1] = cp[2] = gap_grey;
277                                 if( bpp > 3 ) cp[3] = 0xff;
278                         }
279                 }
280         }
281         return title_bar;
282 }
283
284 VFrame *ResourcePixmap::change_picon_alpha(VFrame *picon_frame, int alpha)
285 {
286         uint8_t **picon_rows = picon_frame->get_rows();
287         int pw = picon_frame->get_w(), ph = picon_frame->get_h();
288         int color_model = picon_frame->get_color_model();
289         int bpp = BC_CModels::calculate_pixelsize(color_model);
290         VFrame *frame = new VFrame(pw, ph, BC_RGBA8888);
291         uint8_t **rows = frame->get_rows();
292         if( BC_CModels::has_alpha(color_model) && // fast path
293             BC_CModels::calculate_pixelsize(color_model) == sizeof(unsigned) ) {
294                 unsigned a = alpha << 24;
295                 for( int y=0; y<ph; ++y ) {
296                         unsigned *bp = (unsigned *)picon_rows[y];
297                         unsigned *rp = (unsigned *)rows[y];
298                         for( int i=pw; --i>=0; ++bp,++rp ) *rp = (*bp & 0xffffff) | a;
299                 }
300         }
301         else {
302                 for( int y=0; y<ph; ++y ) {
303                         uint8_t *bp = picon_rows[y], *rp = rows[y];
304                         for( int x=0; x<pw; ++x ) {
305                                 rp[0] = bp[0];  rp[1] = bp[1];
306                                 rp[2] = bp[2];  bp += bpp;
307                                 rp[3] = alpha;  rp += 4;
308                         }
309                 }
310         }
311         return frame;
312 }
313
314 void ResourcePixmap::draw_title(TrackCanvas *canvas,
315         Edit *edit, int64_t edit_x, int64_t edit_w,
316         int64_t pixmap_x, int64_t pixmap_w)
317 {
318 // coords relative to pixmap
319         int64_t total_x = edit_x - pixmap_x, total_w = edit_w;
320         int64_t x = total_x, w = total_w;
321         int left_margin = xS(10);
322
323         if( x < 0 ) { w -= -x; x = 0; }
324         if( w > pixmap_w ) w -= w - pixmap_w;
325
326         VFrame *title_bg = mwindow->theme->get_image("title_bg_data");
327         int color = mwindow->get_title_color(edit);
328         VFrame *title_bar = !color ? title_bg :
329                 change_title_color(title_bg, color);
330         canvas->draw_3segmenth(x, 0, w, total_x, total_w, title_bar, this);
331         if( title_bar != title_bg ) delete title_bar;
332
333         char title[BCTEXTLEN];
334         edit->get_title(title);
335         canvas->set_color(mwindow->theme->title_color);
336         canvas->set_font(mwindow->theme->title_font);
337
338 // Justify the text on the left boundary of the edit if it is visible.
339 // Otherwise justify it on the left side of the screen.
340         int text_x = total_x + left_margin;
341         text_x = MAX(left_margin, text_x);
342 //printf("ResourcePixmap::draw_title 1 %d\n", text_x);
343         canvas->draw_text(text_x, // 2,
344                 canvas->get_text_ascent(mwindow->theme->title_font) + yS(2),
345                 title, strlen(title), this);
346 }
347
348
349 // Need to draw one more x
350 void ResourcePixmap::draw_audio_resource(TrackCanvas *canvas, Edit *edit, int x, int w)
351 {
352         if( w <= 0 ) return;
353         if( !edit->asset && !edit->nested_edl ) return;
354         Indexable *indexable = 0;
355         if( edit->asset ) indexable = edit->asset;
356         if( edit->nested_edl ) indexable = edit->nested_edl;
357 // printf("ResourcePixmap::draw_audio_resource %d x=%d w=%d\n", __LINE__, x, w);
358 SET_TRACE
359
360         IndexState *index_state = indexable->index_state;
361         double asset_over_session = (double)indexable->get_sample_rate() /
362                 mwindow->edl->session->sample_rate;
363 // Develop strategy for drawing
364 // printf("ResourcePixmap::draw_audio_resource %d %p %d\n",
365 // __LINE__,
366 // index_state,
367 // index_state->index_status);
368         switch( index_state->index_status )
369         {
370                 case INDEX_NOTTESTED:
371                         return;
372 // Disabled.  All files have an index.
373 //              case INDEX_TOOSMALL:
374 //                      draw_audio_source(canvas, edit, x, w);
375 //                      break;
376                 case INDEX_BUILDING:
377                 case INDEX_READY: {
378                         IndexFile indexfile(mwindow, indexable);
379                         if( !indexfile.open_index() ) {
380                                 if( index_state->index_zoom >
381                                         mwindow->edl->local_session->zoom_sample *
382                                                 asset_over_session ) {
383                                         draw_audio_source(canvas, edit, x, w);
384                                 }
385                                 else {
386                                         indexfile.draw_index(canvas, this, edit, x, w);
387                                 }
388                                 indexfile.close_index();
389                         }
390                         break;
391                 }
392         }
393         if( !mwindow->preferences->rectify_audio ) {
394                 int center_pixel = calculate_center_pixel(edit->track);
395                 canvas->set_line_dashes(1);
396                 canvas->set_color(mwindow->theme->zero_crossing_color);
397                 canvas->draw_line(x, center_pixel, x + w, center_pixel, this);
398                 canvas->set_line_dashes(0);
399         }
400 }
401
402
403 int ResourcePixmap::calculate_center_pixel(Track *track)
404 {
405         int data_h = track->data_h;
406         int rect_audio = mwindow->preferences->rectify_audio;
407         int center_pixel = !rect_audio ? data_h/2 : data_h;
408         if( track->show_titles() )
409                 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
410         return center_pixel;
411 }
412
413 void ResourcePixmap::draw_audio_source(TrackCanvas *canvas, Edit *edit, int x, int w)
414 {
415         w++;
416         Indexable *indexable = edit->get_source();
417         int center_pixel = calculate_center_pixel(edit->track);
418         int rect_audio = mwindow->preferences->rectify_audio;
419         int data_h = edit->track->data_h;
420         int zoom_y = mwindow->edl->local_session->zoom_y * data_h /
421                         mwindow->edl->local_session->zoom_atrack;
422         int64_t scale_y = !rect_audio ? zoom_y : zoom_y*2;
423         int y_max = center_pixel + scale_y / 2 - 1;
424
425         double project_zoom = mwindow->edl->local_session->zoom_sample;
426         FloatAutos *speed_autos = !edit->track->has_speed() ? 0 :
427                 (FloatAutos *)edit->track->automation->autos[AUTOMATION_SPEED];
428         int64_t edit_position = (x + pixmap_x - edit_x) * project_zoom;
429         int64_t start_position = edit->startsource;
430         start_position += !speed_autos ? edit_position :
431                 speed_autos->automation_integral(edit->startproject, edit_position, PLAY_FORWARD);
432         int64_t end_position = edit->startsource;
433         edit_position = (x + w + pixmap_x - edit_x) * project_zoom;
434         end_position += !speed_autos ? edit_position :
435                 speed_autos->automation_integral(edit->startproject, edit_position, PLAY_FORWARD);
436
437         double session_sample_rate = mwindow->edl->session->sample_rate;
438         double asset_over_session = (double)indexable->get_sample_rate() / session_sample_rate;
439         start_position *= asset_over_session;
440         end_position *= asset_over_session;
441         int sample_size = end_position - start_position;
442         if( sample_size < 0 ) sample_size = 0;
443         int source_samples = sample_size + 1;
444
445 // Single sample zoom
446         if( mwindow->edl->local_session->zoom_sample == 1 ) {
447                 Samples *buffer = 0;
448                 int result = 0;
449                 canvas->set_color(mwindow->theme->audio_color);
450
451                 if( indexable->is_asset ) {
452                         mwindow->gui->unlock_window();
453                         File *source = mwindow->audio_cache->check_out(edit->asset, mwindow->edl);
454                         mwindow->gui->lock_window("draw_audio_source");
455
456                         if( !source ) {
457                                 printf(_("ResourcePixmap::draw_audio_source: failed to check out %s for drawing.\n"), edit->asset->path);
458                                 return;
459                         }
460
461                         source->set_audio_position(start_position);
462                         source->set_channel(edit->channel);
463                         buffer = new Samples(source_samples);
464                         result = source->read_samples(buffer, source_samples);
465                         mwindow->audio_cache->check_in(edit->asset);
466                 }
467                 else {
468                         if( mwindow->gui->render_engine &&
469                                 mwindow->gui->render_engine_id != indexable->id ) {
470                                 delete mwindow->gui->render_engine;
471                                 mwindow->gui->render_engine = 0;
472                         }
473
474                         if( !mwindow->gui->render_engine ) {
475                                 TransportCommand command;
476                                 command.command = NORMAL_FWD;
477                                 command.get_edl()->copy_all(edit->nested_edl);
478                                 command.change_type = CHANGE_ALL;
479                                 command.realtime = 0;
480                                 mwindow->gui->render_engine = new RenderEngine(0,
481                                         mwindow->preferences, 0, 0);
482                                 mwindow->gui->render_engine_id = edit->nested_edl->id;
483                                 mwindow->gui->render_engine->set_acache(mwindow->audio_cache);
484                                 mwindow->gui->render_engine->arm_command(&command);
485                         }
486
487                         if( mwindow->gui->render_engine->arender ) {
488                                 Samples *buffers[MAX_CHANNELS];
489                                 memset(buffers, 0, sizeof(buffers));
490                                 int nch = indexable->get_audio_channels(), ch = edit->channel;
491                                 for( int i=0; i<nch; ++i )
492                                         buffers[i] = new Samples(source_samples);
493                                 mwindow->gui->render_engine->arender->process_buffer(
494                                         buffers, source_samples, start_position);
495                                 for( int i=0; i<nch; ++i )
496                                         if( i != ch ) delete buffers[i];
497                                 buffer = buffers[ch];
498                         }
499                 }
500
501                 if( !result ) {
502                         double *samples = buffer->get_data();
503                         double sample = !rect_audio ? samples[0] : fabs(samples[0]);
504                         int y1 = center_pixel - sample * scale_y / 2;
505                         int y2 = CLIP(y1, 0, y_max);
506
507                         for( int x1=x; x1<w; ++x1 ) {
508                                 int x2 = x1 + 1;
509                                 edit_position = (x1 + pixmap_x - edit_x) * project_zoom;
510                                 int64_t speed_position = edit->startsource;
511                                 speed_position += !speed_autos ? edit_position :
512                                         speed_autos->automation_integral(
513                                                 edit->startproject, edit_position, PLAY_FORWARD);
514                                 int j = speed_position * asset_over_session - start_position;
515                                 CLAMP(j, 0, sample_size);
516                                 int y0 = y2;
517                                 sample = !rect_audio ? samples[j] : fabs(samples[j]);
518                                 y1 = center_pixel - sample * scale_y / 2;
519                                 y2 = CLIP(y1, 0, y_max);
520 //printf("ResourcePixmap::draw_audio_source %d %d %d\n", __LINE__, y1, y2);
521                                 if( !rect_audio )
522                                         canvas->draw_bline(x1, y0, x2, y2, this);
523                                 else
524                                         canvas->draw_bline(x2, center_pixel, x2, y2, this);
525                         }
526                 }
527
528                 delete buffer;
529         }
530         else {
531                 edit_position = (x + pixmap_x - edit_x) * project_zoom;
532                 int64_t speed_position = edit->startsource;
533                 speed_position += !speed_autos ? edit_position :
534                         speed_autos->automation_integral(
535                                 edit->startproject, edit_position, PLAY_FORWARD);
536                 int64_t next_position = asset_over_session * speed_position;
537 // Multiple sample zoom
538                 int first_pixel = 1, prev_y1 = -1, prev_y2 = y_max;
539                 canvas->set_color(mwindow->theme->audio_color);
540                 ++x;
541
542 // Draw each pixel from the cache
543 //printf("ResourcePixmap::draw_audio_source %d x=%d w=%d\n", __LINE__, x, w);
544                 for( int x2=x+w; x<x2; ++x ) {
545                         int64_t prev_position = next_position;
546                         edit_position = (x + pixmap_x - edit_x) * project_zoom;
547                         speed_position = edit->startsource;
548                         speed_position += !speed_autos ? edit_position :
549                                 speed_autos->automation_integral(
550                                         edit->startproject, edit_position, PLAY_FORWARD);
551                         next_position = speed_position * asset_over_session;
552 // Starting sample of pixel relative to asset rate.
553                         WaveCacheItem *item = mwindow->wave_cache->get_wave(indexable->id,
554                                         edit->channel, prev_position, next_position);
555                         if( item ) {
556                                 double item_low = !rect_audio ? item->low : fabs(item->low);
557 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
558                                 int y_lo = (int)(center_pixel - item_low * scale_y / 2);
559                                 int y1 = CLIP(y_lo, 0, y_max);
560                                 double item_high = !rect_audio ? item->high : fabs(item->high);
561                                 int y_hi = (int)(center_pixel - item_high * scale_y / 2);
562                                 int y2 = CLIP(y_hi, 0, y_max);
563                                 if( !first_pixel ) {
564                                         y_lo = MIN(y1,prev_y2);
565                                         y_hi = MAX(y2,prev_y1);
566                                 }
567                                 else {
568                                         first_pixel = 0;
569                                         y_lo = y1;  y_hi = y2;
570                                 }
571                                 prev_y1 = y1;  prev_y2 = y2;
572                                 canvas->draw_line(x, !rect_audio ? y_lo : center_pixel, x, y_hi, this);
573 //printf("ResourcePixmap::draw_audio_source %d %d %d %d\n", __LINE__, x, y1, y2);
574                                 mwindow->wave_cache->unlock();
575                         }
576                         else {
577 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
578                                 gui->resource_thread->add_wave(this,
579                                         canvas->pane->number, indexable, x,
580                                         edit->channel, prev_position, next_position);
581                                 first_pixel = 1;  prev_y1 = -1;  prev_y2 = y_max;
582                         }
583                 }
584         }
585
586         canvas->test_timer();
587 }
588
589 void ResourcePixmap::draw_wave(TrackCanvas *canvas,
590                 int x, double high, double low)
591 {
592         int rect_audio = mwindow->preferences->rectify_audio;
593         if( rect_audio ) { low = fabs(low);  high = fabs(high); }
594         int top_pixel = !mwindow->edl->session->show_titles ? 0 :
595                 mwindow->theme->get_image("title_bg_data")->get_h();
596         int center_pixel = !rect_audio ? data_h/2 + top_pixel : data_h + top_pixel;
597         int zoom_y = mwindow->edl->local_session->zoom_y * (int64_t)data_h /
598                         mwindow->edl->local_session->zoom_atrack;
599         int scale_y = !rect_audio ? zoom_y/2 : zoom_y;
600         int bottom_pixel = top_pixel + data_h;
601         int y1 = (int)(center_pixel - low * scale_y);
602         int y2 = (int)(center_pixel - high * scale_y);
603         CLAMP(y1, top_pixel, bottom_pixel);
604         CLAMP(y2, top_pixel, bottom_pixel);
605         canvas->set_color(mwindow->theme->audio_color);
606         canvas->draw_line(x, !rect_audio ? y1 : bottom_pixel, x, y2, this);
607 }
608
609
610 void ResourcePixmap::draw_video_resource(TrackCanvas *canvas,
611         Edit *edit, int64_t edit_x, int64_t edit_w, int64_t pixmap_x, int64_t pixmap_w,
612         int refresh_x, int refresh_w, int mode)
613 {
614 //PRINT_TRACE
615 //BC_Signals::dump_stack();
616
617 // pixels spanned by a picon
618         int64_t picon_w = Units::round(edit->picon_w());
619         int64_t picon_h = edit->picon_h();
620 //      if( picon_w <= 0 || picon_w > edit_w ) return;
621 // Don't draw video if picon is empty, or edit only hairline
622         if( picon_w < 1 || edit_w < 2 ) return;
623 // or bigger than edit and fills at less than 1.5 percent timeline
624         if( picon_w > edit_w && edit_w < canvas->get_w()/64 ) return;
625
626 // Frames spanned by a picon
627         double frame_w = edit->frame_w();
628 // pixels spanned by a frame
629         if( frame_w < picon_w ) frame_w = picon_w;
630 // Current pixel relative to pixmap
631         int y = 0;
632         if( edit->track->show_titles() )
633                 y += mwindow->theme->get_image("title_bg_data")->get_h();
634
635 // Frame in project touched by current pixel
636         FloatAutos *speed_autos = !edit->track->has_speed() ? 0 :
637                 (FloatAutos *)edit->track->automation->autos[AUTOMATION_SPEED];
638         Indexable *indexable = edit->get_source();
639         double session_sample_rate = mwindow->edl->session->sample_rate;
640         double project_zoom = mwindow->edl->local_session->zoom_sample / session_sample_rate;
641         int skip_frames = Units::to_int64(((int64_t)refresh_x + pixmap_x - edit_x) / frame_w);
642         int x = Units::to_int64(skip_frames * frame_w) + edit_x - pixmap_x;
643
644 // Draw only cached frames
645         while( x < refresh_x + refresh_w ) {
646                 int64_t edit_position =
647                         edit->track->to_units((x + pixmap_x - edit_x) * project_zoom, 0);
648                 int64_t speed_position = edit->startsource;
649                 speed_position += !speed_autos ? edit_position :
650                          speed_autos->automation_integral(
651                                 edit->startproject, edit_position, PLAY_FORWARD);
652                 VFrame *picon_frame = indexable->id < 0 ? 0 :
653                         mwindow->frame_cache->get_frame_ptr(speed_position, edit->channel,
654                                 mwindow->edl->session->frame_rate, BC_RGB888,
655                                 picon_w, picon_h, indexable->id);
656                 int bg_color = gui->get_bg_color();
657                 if( picon_frame ) {
658                         VFrame *frame = picon_frame;
659                         int color = mwindow->get_title_color(edit);
660                         if( color ) {
661                                 int alpha = (~color >> 24) & 0xff;
662                                 frame = change_picon_alpha(picon_frame, alpha);
663                                 gui->set_bg_color(color & 0xffffff);
664                         }
665                         draw_vframe(frame, x, y, picon_w, picon_h, 0, 0);
666                         if( frame != picon_frame ) {
667                                 delete frame;
668                                 gui->set_bg_color(bg_color);
669                         }
670                         mwindow->frame_cache->unlock();
671                 }
672                 else if( mode != IGNORE_THREAD ) {
673 // Set picon thread to draw in background
674 // printf("ResourcePixmap::draw_video_resource %d %d %lld\n",
675 // __LINE__, mwindow->frame_cache->total(), source_frame);
676                         gui->resource_thread->add_picon(this, canvas->pane->number, x, y,
677                                 picon_w, picon_h, mwindow->edl->session->frame_rate,
678                                 speed_position, edit->channel, indexable);
679                 }
680                 x += frame_w;
681                 canvas->test_timer();
682         }
683 }
684
685 #include "strack.h"
686
687 void ResourcePixmap::draw_subttl_resource(TrackCanvas *canvas, Edit *edit, int x, int w)
688 {
689         SEdit *sedit = (SEdit *)edit;
690         char *text = sedit->get_text();
691         if( !*text || w < xS(10) ) return;
692         int data_h = edit->track->data_h, center_pixel = data_h/2;
693         if( edit->track->show_titles() )
694                 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
695         int x0 = edit_x;
696         if( x0 < 0 ) x0 = -x0;
697         int x1 = (int)(pixmap_x - x0 + x);
698         int font = data_h >= yS(24) ? MEDIUMFONT : SMALLFONT, color = WHITE;
699         int ascent = canvas->get_text_ascent(font);
700         int y1 = center_pixel + ascent/2;
701         if( y1 < 0 ) y1 = 0;
702         canvas->set_font(font);
703         canvas->set_color(color);
704         canvas->draw_text(x1, y1, text, -1, this);
705 }
706
707 void ResourcePixmap::dump()
708 {
709         printf("ResourcePixmap %p\n", this);
710         printf(" edit %jx edit_x %jd pixmap_x %jd pixmap_w %jd visible %d\n",
711                 edit_id, edit_x, pixmap_x, pixmap_w, visible);
712 }
713