4 * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
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.
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.
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
28 #include "automation.h"
30 #include "bcsignals.h"
33 #include "bccmodels.h"
38 #include "edlsession.h"
40 #include "filesystem.h"
41 #include "floatauto.h"
42 #include "floatautos.h"
43 #include "framecache.h"
44 #include "indexfile.h"
46 #include "localsession.h"
48 #include "mwindowgui.h"
49 #include "preferences.h"
50 #include "renderengine.h"
51 #include "resourcethread.h"
52 #include "resourcepixmap.h"
55 #include "timelinepane.h"
57 #include "trackcanvas.h"
58 #include "transportque.h"
61 #include "wavecache.h"
64 ResourcePixmap::ResourcePixmap(MWindow *mwindow,
70 : BC_Pixmap(gui, w, h)
74 this->mwindow = mwindow;
76 this->pane_number = pane_number;
77 startsource = edit->startsource;
78 data_type = edit->track->data_type;
80 source_framerate = edit->asset->frame_rate;
81 source_samplerate = edit->asset->sample_rate;
84 if( edit->nested_edl ) {
85 source_framerate = edit->nested_edl->session->frame_rate;
86 source_samplerate = edit->nested_edl->session->sample_rate;
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;
94 ResourcePixmap::~ResourcePixmap()
99 void ResourcePixmap::reset()
111 void ResourcePixmap::resize(int w, int h)
113 int new_w = (w > get_w()) ? w : get_w();
114 int new_h = (h > get_h()) ? h : get_h();
116 BC_Pixmap::resize(new_w, new_h);
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)
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;
129 startsource = edit->startsource;
131 source_framerate = edit->asset->frame_rate;
133 if( edit->nested_edl )
134 source_framerate = edit->nested_edl->session->frame_rate;
136 source_samplerate = edit->asset->sample_rate;
137 else if( edit->nested_edl )
138 source_samplerate = edit->nested_edl->session->sample_rate;
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;
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)
152 // Get new areas to fill in relative to pixmap
153 // Area to redraw relative to pixmap
157 // Ignore if called by resourcethread.
158 // if( mode == IGNORE_THREAD ) return;
161 if( edit->track->show_titles() )
162 y += mwindow->theme->get_image("title_bg_data")->get_h();
164 // If want indexes only & index can't be drawn, don't do anything.
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();
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 *
191 /* Incremental drawing is not possible with resource thread */
194 refresh_w = pixmap_w;
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);
204 //printf("ResourcePixmap::draw_data 70\n");
207 // Draw media which already exists
208 Track *track = edit->track;
210 switch( track->data_type )
213 draw_audio_resource(canvas,
214 edit, refresh_x, refresh_w);
218 draw_video_resource(canvas, edit, edit_x, edit_w,
219 pixmap_x, pixmap_w, refresh_x, refresh_w,
224 draw_subttl_resource(canvas, edit,
225 refresh_x, refresh_w);
233 VFrame *ResourcePixmap::change_title_color(VFrame *title_bg, int color)
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 const uint8_t gap_grey = 0x4a;
243 uint8_t *cp = bar_rows[0];
244 for( int x=0; x<tw; ++x ) {
245 cp[0] = cp[1] = cp[2] = gap_grey;
246 if( bpp > 3 ) cp[3] = 0xff;
250 for( int y=1; y<th; ++y ) {
251 uint8_t *cp = bar_rows[y];
253 cp[0] = cp[1] = cp[2] = gap_grey;
254 if( bpp > 3 ) cp[3] = 0xff;
257 for( int x=1; x<tw1; ++x ) {
258 cp[0] = cr; cp[1] = cg; cp[2] = cb;
259 if( bpp > 3 ) cp[3] = 0xff;
263 cp[0] = cp[1] = cp[2] = gap_grey;
264 if( bpp > 3 ) cp[3] = 0xff;
270 VFrame *ResourcePixmap::change_picon_alpha(VFrame *picon_frame, int alpha)
272 uint8_t **picon_rows = picon_frame->get_rows();
273 int w = picon_frame->get_w(), h = picon_frame->get_h();
274 int color_model = picon_frame->get_color_model();
275 int bpp = BC_CModels::calculate_pixelsize(color_model);
276 VFrame *frame = new VFrame(w, h, BC_RGBA8888);
277 uint8_t **rows = frame->get_rows();
278 for( int y=0; y<h; ++y ) {
279 uint8_t *bp = picon_rows[y], *rp = rows[y];
280 for( int x=0; x<w; ++x ) {
281 rp[0] = bp[0]; rp[1] = bp[1];
282 rp[2] = bp[2]; bp += bpp;
283 rp[3] = alpha; rp += 4;
289 void ResourcePixmap::draw_title(TrackCanvas *canvas,
290 Edit *edit, int64_t edit_x, int64_t edit_w,
291 int64_t pixmap_x, int64_t pixmap_w)
293 // coords relative to pixmap
294 int64_t total_x = edit_x - pixmap_x, total_w = edit_w;
295 int64_t x = total_x, w = total_w;
296 int left_margin = 10;
298 if( x < 0 ) { w -= -x; x = 0; }
299 if( w > pixmap_w ) w -= w - pixmap_w;
301 VFrame *title_bg = mwindow->theme->get_image("title_bg_data");
302 int color = mwindow->get_title_color(edit);
303 VFrame *title_bar = !color ? title_bg :
304 change_title_color(title_bg, color);
305 canvas->draw_3segmenth(x, 0, w, total_x, total_w, title_bar, this);
306 if( title_bar != title_bg ) delete title_bar;
308 char title[BCTEXTLEN];
309 edit->get_title(title);
310 canvas->set_color(mwindow->theme->title_color);
311 canvas->set_font(mwindow->theme->title_font);
313 // Justify the text on the left boundary of the edit if it is visible.
314 // Otherwise justify it on the left side of the screen.
315 int text_x = total_x + left_margin;
316 text_x = MAX(left_margin, text_x);
317 //printf("ResourcePixmap::draw_title 1 %d\n", text_x);
318 canvas->draw_text(text_x, // 2,
319 canvas->get_text_ascent(mwindow->theme->title_font) + 2,
320 title, strlen(title), this);
324 // Need to draw one more x
325 void ResourcePixmap::draw_audio_resource(TrackCanvas *canvas, Edit *edit, int x, int w)
328 if( !edit->asset && !edit->nested_edl ) return;
329 Indexable *indexable = 0;
330 if( edit->asset ) indexable = edit->asset;
331 if( edit->nested_edl ) indexable = edit->nested_edl;
332 // printf("ResourcePixmap::draw_audio_resource %d x=%d w=%d\n", __LINE__, x, w);
335 IndexState *index_state = indexable->index_state;
336 double asset_over_session = (double)indexable->get_sample_rate() /
337 mwindow->edl->session->sample_rate;
339 // Develop strategy for drawing
340 // printf("ResourcePixmap::draw_audio_resource %d %p %d\n",
343 // index_state->index_status);
344 switch( index_state->index_status )
346 case INDEX_NOTTESTED:
349 // Disabled. All files have an index.
350 // case INDEX_TOOSMALL:
351 // draw_audio_source(canvas, edit, x, w);
356 IndexFile indexfile(mwindow, indexable);
357 if( !indexfile.open_index() ) {
358 if( index_state->index_zoom >
359 mwindow->edl->local_session->zoom_sample *
360 asset_over_session ) {
361 //printf("ResourcePixmap::draw_audio_resource %d\n", __LINE__);
363 draw_audio_source(canvas, edit, x, w);
366 //printf("ResourcePixmap::draw_audio_resource %d\n", __LINE__);
367 indexfile.draw_index(canvas,
375 indexfile.close_index();
384 void ResourcePixmap::draw_audio_source(TrackCanvas *canvas, Edit *edit, int x, int w)
387 Indexable *indexable = edit->get_source();
388 int rect_audio = mwindow->preferences->rectify_audio;
389 int center_pixel = !rect_audio ?
390 mwindow->edl->local_session->zoom_track / 2 :
391 mwindow->edl->local_session->zoom_track ;
392 if( edit->track->show_titles() )
393 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
394 int64_t scale_y = !rect_audio ?
395 mwindow->edl->local_session->zoom_y :
396 mwindow->edl->local_session->zoom_y * 2;
397 int y_max = center_pixel + scale_y / 2 - 1;
399 double project_zoom = mwindow->edl->local_session->zoom_sample;
400 FloatAutos *speed_autos = !edit->track->has_speed() ? 0 :
401 (FloatAutos *)edit->track->automation->autos[AUTOMATION_SPEED];
402 int64_t edit_position = (x + pixmap_x - edit_x) * project_zoom;
403 int64_t start_position = edit->startsource;
404 start_position += !speed_autos ? edit_position :
405 speed_autos->automation_integral(edit->startproject, edit_position, PLAY_FORWARD);
406 int64_t end_position = edit->startsource;
407 edit_position = (x + w + pixmap_x - edit_x) * project_zoom;
408 end_position += !speed_autos ? edit_position :
409 speed_autos->automation_integral(edit->startproject, edit_position, PLAY_FORWARD);
411 double session_sample_rate = mwindow->edl->session->sample_rate;
412 double asset_over_session = (double)indexable->get_sample_rate() / session_sample_rate;
413 start_position *= asset_over_session;
414 end_position *= asset_over_session;
415 int sample_size = end_position - start_position;
416 if( sample_size < 0 ) sample_size = 0;
417 int source_samples = sample_size + 1;
419 // Single sample zoom
420 if( mwindow->edl->local_session->zoom_sample == 1 ) {
423 canvas->set_color(mwindow->theme->audio_color);
425 if( indexable->is_asset ) {
426 mwindow->gui->unlock_window();
427 File *source = mwindow->audio_cache->check_out(edit->asset, mwindow->edl);
428 mwindow->gui->lock_window("draw_audio_source");
431 printf(_("ResourcePixmap::draw_audio_source: failed to check out %s for drawing.\n"), edit->asset->path);
435 source->set_audio_position(start_position);
436 source->set_channel(edit->channel);
437 buffer = new Samples(source_samples);
438 result = source->read_samples(buffer, source_samples);
439 mwindow->audio_cache->check_in(edit->asset);
442 if( mwindow->gui->render_engine &&
443 mwindow->gui->render_engine_id != indexable->id ) {
444 delete mwindow->gui->render_engine;
445 mwindow->gui->render_engine = 0;
448 if( !mwindow->gui->render_engine ) {
449 TransportCommand command;
450 command.command = NORMAL_FWD;
451 command.get_edl()->copy_all(edit->nested_edl);
452 command.change_type = CHANGE_ALL;
453 command.realtime = 0;
454 mwindow->gui->render_engine = new RenderEngine(0,
455 mwindow->preferences, 0, 0);
456 mwindow->gui->render_engine_id = edit->nested_edl->id;
457 mwindow->gui->render_engine->set_acache(mwindow->audio_cache);
458 mwindow->gui->render_engine->arm_command(&command);
461 if( mwindow->gui->render_engine->arender ) {
462 Samples *buffers[MAX_CHANNELS];
463 memset(buffers, 0, sizeof(buffers));
464 int nch = indexable->get_audio_channels(), ch = edit->channel;
465 for( int i=0; i<nch; ++i )
466 buffers[i] = new Samples(source_samples);
467 mwindow->gui->render_engine->arender->process_buffer(
468 buffers, source_samples, start_position);
469 for( int i=0; i<nch; ++i )
470 if( i != ch ) delete buffers[i];
471 buffer = buffers[ch];
476 double *samples = buffer->get_data();
477 double sample = !rect_audio ? samples[0] : fabs(samples[0]);
478 int y1 = center_pixel - sample * scale_y / 2;
479 int y2 = CLIP(y1, 0, y_max);
481 for( int x1=x; x1<w; ++x1 ) {
483 edit_position = (x1 + pixmap_x - edit_x) * project_zoom;
484 int64_t speed_position = edit->startsource;
485 speed_position += !speed_autos ? edit_position :
486 speed_autos->automation_integral(
487 edit->startproject, edit_position, PLAY_FORWARD);
488 int j = speed_position * asset_over_session - start_position;
489 CLAMP(j, 0, sample_size);
491 sample = !rect_audio ? samples[j] : fabs(samples[j]);
492 y1 = center_pixel - sample * scale_y / 2;
493 y2 = CLIP(y1, 0, y_max);
494 //printf("ResourcePixmap::draw_audio_source %d %d %d\n", __LINE__, y1, y2);
496 canvas->draw_line(x1, y0, x2, y2, this);
498 canvas->draw_line(x2, center_pixel, x2, y2, this);
505 edit_position = (x + pixmap_x - edit_x) * project_zoom;
506 int64_t speed_position = edit->startsource;
507 speed_position += !speed_autos ? edit_position :
508 speed_autos->automation_integral(
509 edit->startproject, edit_position, PLAY_FORWARD);
510 int64_t next_position = asset_over_session * speed_position;
511 // Multiple sample zoom
512 int first_pixel = 1, prev_y1 = -1, prev_y2 = y_max;
513 canvas->set_color(mwindow->theme->audio_color);
516 // Draw each pixel from the cache
517 //printf("ResourcePixmap::draw_audio_source %d x=%d w=%d\n", __LINE__, x, w);
518 for( int x2=x+w; x<x2; ++x ) {
519 int64_t prev_position = next_position;
520 edit_position = (x + pixmap_x - edit_x) * project_zoom;
521 speed_position = edit->startsource;
522 speed_position += !speed_autos ? edit_position :
523 speed_autos->automation_integral(
524 edit->startproject, edit_position, PLAY_FORWARD);
525 next_position = speed_position * asset_over_session;
526 // Starting sample of pixel relative to asset rate.
527 WaveCacheItem *item = mwindow->wave_cache->get_wave(indexable->id,
528 edit->channel, prev_position, next_position);
530 double item_low = !rect_audio ? item->low : fabs(item->low);
531 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
532 int y_lo = (int)(center_pixel - item_low * scale_y / 2);
533 int y1 = CLIP(y_lo, 0, y_max);
534 double item_high = !rect_audio ? item->high : fabs(item->high);
535 int y_hi = (int)(center_pixel - item_high * scale_y / 2);
536 int y2 = CLIP(y_hi, 0, y_max);
538 y_lo = MIN(y1,prev_y2);
539 y_hi = MAX(y2,prev_y1);
543 y_lo = y1; y_hi = y2;
545 prev_y1 = y1; prev_y2 = y2;
546 canvas->draw_line(x, !rect_audio ? y_lo : center_pixel, x, y_hi, this);
547 //printf("ResourcePixmap::draw_audio_source %d %d %d %d\n", __LINE__, x, y1, y2);
548 mwindow->wave_cache->unlock();
551 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
552 gui->resource_thread->add_wave(this,
553 canvas->pane->number, indexable, x,
554 edit->channel, prev_position, next_position);
555 first_pixel = 1; prev_y1 = -1; prev_y2 = y_max;
560 canvas->test_timer();
563 void ResourcePixmap::draw_wave(TrackCanvas *canvas,
564 int x, double high, double low)
566 int rect_audio = mwindow->preferences->rectify_audio;
567 if( rect_audio ) { low = fabs(low); high = fabs(high); }
568 int top_pixel = mwindow->edl->session->show_titles ? 0 :
569 mwindow->theme->get_image("title_bg_data")->get_h();
570 int center_pixel = !rect_audio ?
571 mwindow->edl->local_session->zoom_track / 2 + top_pixel :
572 mwindow->edl->local_session->zoom_track + top_pixel ;
573 int scale_y = !rect_audio ?
574 mwindow->edl->local_session->zoom_y / 2 :
575 mwindow->edl->local_session->zoom_y ;
576 int bottom_pixel = top_pixel + mwindow->edl->local_session->zoom_track;
577 int y1 = (int)(center_pixel - low * scale_y);
578 int y2 = (int)(center_pixel - high * scale_y);
579 CLAMP(y1, top_pixel, bottom_pixel);
580 CLAMP(y2, top_pixel, bottom_pixel);
581 canvas->set_color(mwindow->theme->audio_color);
582 canvas->draw_line(x, !rect_audio ? y1 : bottom_pixel, x, y2, this);
586 void ResourcePixmap::draw_video_resource(TrackCanvas *canvas,
587 Edit *edit, int64_t edit_x, int64_t edit_w, int64_t pixmap_x, int64_t pixmap_w,
588 int refresh_x, int refresh_w, int mode)
591 //BC_Signals::dump_stack();
593 // pixels spanned by a picon
594 int64_t picon_w = Units::round(edit->picon_w());
595 int64_t picon_h = edit->picon_h();
596 // if( picon_w <= 0 || picon_w > edit_w ) return;
597 // Don't draw video if picon is empty, or edit only hairline
598 if( picon_w < 1 || edit_w < 2 ) return;
599 // or bigger than edit and fills at less than 1.5 percent timeline
600 if( picon_w > edit_w && edit_w < canvas->get_w()/64 ) return;
602 // Frames spanned by a picon
603 double frame_w = edit->frame_w();
604 // pixels spanned by a frame
605 if( frame_w < picon_w ) frame_w = picon_w;
606 // Current pixel relative to pixmap
608 if( edit->track->show_titles() )
609 y += mwindow->theme->get_image("title_bg_data")->get_h();
611 // Frame in project touched by current pixel
612 FloatAutos *speed_autos = !edit->track->has_speed() ? 0 :
613 (FloatAutos *)edit->track->automation->autos[AUTOMATION_SPEED];
614 Indexable *indexable = edit->get_source();
615 double session_sample_rate = mwindow->edl->session->sample_rate;
616 double project_zoom = mwindow->edl->local_session->zoom_sample / session_sample_rate;
617 int skip_frames = Units::to_int64(((int64_t)refresh_x + pixmap_x - edit_x) / frame_w);
618 int x = Units::to_int64(skip_frames * frame_w) + edit_x - pixmap_x;
620 // Draw only cached frames
621 while( x < refresh_x + refresh_w ) {
622 int64_t edit_position =
623 edit->track->to_units((x + pixmap_x - edit_x) * project_zoom, 0);
624 int64_t speed_position = edit->startsource;
625 speed_position += !speed_autos ? edit_position :
626 speed_autos->automation_integral(
627 edit->startproject, edit_position, PLAY_FORWARD);
628 VFrame *picon_frame = indexable->id < 0 ? 0 :
629 mwindow->frame_cache->get_frame_ptr(speed_position, edit->channel,
630 mwindow->edl->session->frame_rate, BC_RGB888,
631 picon_w, picon_h, indexable->id);
632 int bg_color = gui->get_bg_color();
634 VFrame *frame = picon_frame;
635 int color = mwindow->get_title_color(edit);
637 int alpha = (~color >> 24) & 0xff;
638 frame = change_picon_alpha(picon_frame, alpha);
639 gui->set_bg_color(color & 0xffffff);
641 draw_vframe(frame, x, y, picon_w, picon_h, 0, 0);
642 if( frame != picon_frame ) {
644 gui->set_bg_color(bg_color);
646 mwindow->frame_cache->unlock();
648 else if( mode != IGNORE_THREAD ) {
649 // Set picon thread to draw in background
650 // printf("ResourcePixmap::draw_video_resource %d %d %lld\n",
651 // __LINE__, mwindow->frame_cache->total(), source_frame);
652 gui->resource_thread->add_picon(this, canvas->pane->number, x, y,
653 picon_w, picon_h, mwindow->edl->session->frame_rate,
654 speed_position, edit->channel, indexable);
657 canvas->test_timer();
663 void ResourcePixmap::draw_subttl_resource(TrackCanvas *canvas, Edit *edit, int x, int w)
665 SEdit *sedit = (SEdit *)edit;
666 char *text = sedit->get_text();
667 if( !*text || w < 10 ) return;
668 int center_pixel = canvas->resource_h() / 2;
669 if( edit->track->show_titles() )
670 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
671 int64_t scale_y = mwindow->edl->local_session->zoom_y;
673 if( x0 < 0 ) x0 = -x0;
674 int x1 = (int)(pixmap_x - x0 + x);
675 int y_max = center_pixel + scale_y / 2 - 1;
676 int font = MEDIUMFONT, color = WHITE;
677 canvas->set_font(font);
678 canvas->set_color(color);
679 int ch = canvas->get_text_height(font);
680 int hh = canvas->get_text_height(font,text) + ch/2;
681 int y1 = y_max - hh - 10;
683 canvas->draw_text(x1, y1, text, -1, this);
686 void ResourcePixmap::dump()
688 printf("ResourcePixmap %p\n", this);
689 printf(" edit %jx edit_x %jd pixmap_x %jd pixmap_w %jd visible %d\n",
690 edit_id, edit_x, pixmap_x, pixmap_w, visible);