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 "renderengine.h"
50 #include "resourcethread.h"
51 #include "resourcepixmap.h"
54 #include "timelinepane.h"
56 #include "trackcanvas.h"
57 #include "transportque.h"
60 #include "wavecache.h"
63 ResourcePixmap::ResourcePixmap(MWindow *mwindow,
69 : BC_Pixmap(gui, w, h)
73 this->mwindow = mwindow;
75 this->pane_number = pane_number;
76 startsource = edit->startsource;
77 data_type = edit->track->data_type;
79 source_framerate = edit->asset->frame_rate;
80 source_samplerate = edit->asset->sample_rate;
83 if( edit->nested_edl ) {
84 source_framerate = edit->nested_edl->session->frame_rate;
85 source_samplerate = edit->nested_edl->session->sample_rate;
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;
93 ResourcePixmap::~ResourcePixmap()
98 void ResourcePixmap::reset()
110 void ResourcePixmap::resize(int w, int h)
112 int new_w = (w > get_w()) ? w : get_w();
113 int new_h = (h > get_h()) ? h : get_h();
115 BC_Pixmap::resize(new_w, new_h);
119 void ResourcePixmap::draw_data(TrackCanvas *canvas,
129 // Get new areas to fill in relative to pixmap
130 // Area to redraw relative to pixmap
134 // Ignore if called by resourcethread.
135 // if( mode == IGNORE_THREAD ) return;
138 if( mwindow->edl->session->show_titles )
139 y += mwindow->theme->get_image("title_bg_data")->get_h();
140 Track *track = edit->edits->track;
143 // If want indexes only & index can't be drawn, don't do anything.
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();
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 *
172 /* Incremental drawing is not possible with resource thread */
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) ||
185 // Redraw the whole thing.
187 refresh_w = pixmap_w;
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;
195 // Moved completely off the pixmap
196 if( refresh_w > this->pixmap_w ) {
197 refresh_w = this->pixmap_w;
204 mwindow->edl->local_session->zoom_track,
210 // Start translated left
211 if( pixmap_w == this->pixmap_w && edit_x > this->edit_x && edit_w != pixmap_w ) {
213 refresh_w = edit_x - this->edit_x;
215 // Moved completely off the pixmap
216 if( refresh_w > this->pixmap_w ) {
217 refresh_w = this->pixmap_w;
222 this->pixmap_w - refresh_w,
223 mwindow->edl->local_session->zoom_track,
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;
235 if( refresh_w >= pixmap_w ) {
237 refresh_w = pixmap_w;
240 copy_area(this->edit_x - edit_x,
242 pixmap_w - refresh_w,
243 mwindow->edl->local_session->zoom_track,
249 // Start translated right and reduced in size on the right.
250 if( pixmap_w < this->pixmap_w && edit_x < this->edit_x ) {
254 copy_area(this->pixmap_w - pixmap_w,
257 mwindow->edl->local_session->zoom_track,
262 // Start translated left and pixmap came off left side
263 if( edit_x >= 0 && this->edit_x < 0 ) {
265 refresh_w = -this->edit_x;
267 if( refresh_w > pixmap_w ) {
268 refresh_w = pixmap_w;
274 mwindow->edl->local_session->zoom_track,
280 // Start translated left and reduced in size on the right
281 if( pixmap_w < this->pixmap_w && edit_x > this->edit_x ) {
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;
291 // Moved completely off new pixmap
292 if( refresh_w > pixmap_w ) {
293 refresh_w = pixmap_w;
300 mwindow->edl->local_session->zoom_track,
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;
312 // Start translated left and increased in size on the right
313 if( pixmap_w > this->pixmap_w && edit_x > this->edit_x ) {
315 refresh_w = edit_x - this->edit_x;
317 // Moved completely off new pixmap
318 if( refresh_w > this->pixmap_w ) {
319 refresh_w = pixmap_w;
327 mwindow->edl->local_session->zoom_track,
334 // Update pixmap settings
335 this->edit_id = edit->id;
336 this->startsource = edit->startsource;
339 this->source_framerate = edit->asset->frame_rate;
341 if( edit->nested_edl )
342 this->source_framerate = edit->nested_edl->session->frame_rate;
345 this->source_samplerate = edit->asset->sample_rate;
347 if( edit->nested_edl )
348 this->source_samplerate = edit->nested_edl->session->sample_rate;
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;
362 // Draw background image
364 mwindow->theme->draw_resource_bg(canvas,
371 refresh_x + refresh_w,
372 mwindow->edl->local_session->zoom_track + y);
373 //printf("ResourcePixmap::draw_data 70\n");
376 // Draw media which already exists
378 switch( track->data_type )
381 draw_audio_resource(canvas,
388 draw_video_resource(canvas,
400 draw_subttl_resource(canvas,
410 if( mwindow->edl->session->show_titles )
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)
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;
429 if( x < 0 ) { w -= -x; x = 0; }
430 if( w > pixmap_w ) w -= w - pixmap_w;
432 canvas->draw_3segmenth(x, 0, w, total_x, total_w,
433 mwindow->theme->get_image("title_bg_data"), this);
435 // if( total_x > -BC_INFINITY ) {
436 char title[BCTEXTLEN];
437 char channel[BCTEXTLEN];
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);
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);
454 else if( edit->asset ) {
455 fs.extract_name(title, edit->asset->path);
456 sprintf(channel, " #%d", edit->channel + 1);
457 strcat(title, channel);
460 canvas->set_color(mwindow->theme->title_color);
461 canvas->set_font(mwindow->theme->title_font);
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);
475 // Need to draw one more x
476 void ResourcePixmap::draw_audio_resource(TrackCanvas *canvas, Edit *edit, int x, int w)
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);
486 IndexState *index_state = indexable->index_state;
487 double asset_over_session = (double)indexable->get_sample_rate() /
488 mwindow->edl->session->sample_rate;
490 // Develop strategy for drawing
491 // printf("ResourcePixmap::draw_audio_resource %d %p %d\n",
494 // index_state->index_status);
495 switch( index_state->index_status )
497 case INDEX_NOTTESTED:
500 // Disabled. All files have an index.
501 // case INDEX_TOOSMALL:
502 // draw_audio_source(canvas, edit, x, w);
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__);
514 draw_audio_source(canvas, edit, x, w);
517 //printf("ResourcePixmap::draw_audio_resource %d\n", __LINE__);
518 indexfile.draw_index(canvas,
526 indexfile.close_index();
551 void ResourcePixmap::draw_audio_source(TrackCanvas *canvas,
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;
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;
580 // Single sample zoom
581 if( mwindow->edl->local_session->zoom_sample == 1 ) {
582 Samples *buffer = new Samples(total_source_samples);
584 canvas->set_color(mwindow->theme->audio_color);
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");
592 printf(_("ResourcePixmap::draw_audio_source: failed to check out %s for drawing.\n"), edit->asset->path);
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);
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;
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);
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);
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));
635 for( int i = 0; i < indexable->get_audio_channels(); i++ ) {
636 delete temp_buffer[i];
641 double *samples = buffer->get_data();
642 int y1 = center_pixel - samples[0] * scale_y / 2;
643 int y2 = CLIP(y1, 0, y_max);
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);
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);
663 // Multiple sample zoom
669 canvas->set_color(mwindow->theme->audio_color);
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;
676 // Draw each pixel from the cache
677 //printf("ResourcePixmap::draw_audio_source %d x=%d w=%d\n", __LINE__, x, w);
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);
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);
695 y_lo = MIN(y1,prev_y2);
696 y_hi = MAX(y2,prev_y1);
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();
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);
720 canvas->test_timer();
723 void ResourcePixmap::draw_wave(TrackCanvas *canvas, int x, double high, double low)
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);
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)
746 //BC_Signals::dump_stack();
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;
757 // pixels spanned by a frame
758 double frame_w = edit->frame_w();
760 // Frames spanned by a picon
761 double frames_per_picon = edit->frames_per_picon();
763 // Current pixel relative to pixmap
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;
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);
779 project_frame = Units::to_int64((double)((int64_t)refresh_x + pixmap_x - edit_x) /
781 x = Units::round((double)project_frame * frame_w + edit_x - pixmap_x);
784 FloatAutos *speed_autos = (FloatAutos *)edit->track->automation->autos[AUTOMATION_SPEED];
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();
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);
802 if( picon_frame != 0 ) {
806 // Set picon thread to draw in background
807 if( mode != IGNORE_THREAD ) {
808 // printf("ResourcePixmap::draw_video_resource %d %d %lld\n",
810 // mwindow->frame_cache->total(),
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);
819 draw_vframe(picon_frame, x, y, picon_w, picon_h, 0, 0);
821 // Unlock the get_frame_ptr command
823 mwindow->frame_cache->unlock();
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));
830 x += Units::round(frame_w);
831 project_frame = (int64_t)((double)(x + pixmap_x - edit_x) / frame_w);
835 canvas->test_timer();
841 void ResourcePixmap::draw_subttl_resource(TrackCanvas *canvas, Edit *edit, int x, int w)
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;
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;
861 canvas->draw_text(x1, y1, text, -1, this);
864 void ResourcePixmap::dump()
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);