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