From: Good Guy Date: Thu, 14 Nov 2019 03:07:00 +0000 (-0700) Subject: rework canvas zoom, add 3 plugins from 7.2, tweak cwdw boundry, vdevicex11 dupl close... X-Git-Tag: 2019-11~5 X-Git-Url: https://git.cinelerra-gg.org/git/?a=commitdiff_plain;h=0e16112661802284c0d2c9eb8d1df84141125e91;p=goodguy%2Fcinelerra.git rework canvas zoom, add 3 plugins from 7.2, tweak cwdw boundry, vdevicex11 dupl close bug, lv2ui init_resources bug --- diff --git a/cinelerra-5.1/cinelerra/Makefile b/cinelerra-5.1/cinelerra/Makefile index 4652f02f..b891b20e 100644 --- a/cinelerra-5.1/cinelerra/Makefile +++ b/cinelerra-5.1/cinelerra/Makefile @@ -607,7 +607,7 @@ $(OBJDIR)/%.o: %.C #lv2 ifneq ($(WANT_LV2),no) -GTK2_INCS := `pkg-config --cflags gtk+-2.0` +GTK2_INCS := `pkg-config --cflags gtk+-2.0` -Wno-deprecated-declarations GTK2_LIBS := `pkg-config --libs gtk+-2.0` $(OBJDIR)/pluginlv2ui.o: pluginlv2ui.C diff --git a/cinelerra-5.1/cinelerra/canvas.C b/cinelerra-5.1/cinelerra/canvas.C index cd59b62c..850177b4 100644 --- a/cinelerra-5.1/cinelerra/canvas.C +++ b/cinelerra-5.1/cinelerra/canvas.C @@ -142,105 +142,45 @@ void Canvas::set_fullscreen(int value) // Get dimensions given a zoom void Canvas::calculate_sizes(float aspect_ratio, - int output_w, - int output_h, - float zoom, - int &w, - int &h) + int output_w, int output_h, float zoom, + int &w, int &h) { // Horizontal stretch - if((float)output_w / output_h <= aspect_ratio) - { - w = (int)((float)output_h * aspect_ratio * zoom); - h = (int)((float)output_h * zoom); + if( (float)output_w/output_h <= aspect_ratio ) { + w = (float)output_h * aspect_ratio * zoom; + h = (float)output_h * zoom; } - else + else { // Vertical stretch - { - h = (int)((float)output_w / aspect_ratio * zoom); - w = (int)((float)output_w * zoom); + h = (float)output_w / aspect_ratio * zoom; + w = (float)output_w * zoom; } } -float Canvas::get_x_offset(EDL *edl, - int single_channel, - float zoom_x, - float conformed_w, - float conformed_h) +float Canvas::get_x_offset(EDL *edl, int single_channel, + float zoom_x, float conformed_w, float conformed_h) { - if(use_scrollbars) - { - if(xscroll) - { -// If the projection is smaller than the canvas, this forces it in the center. -// if(conformed_w < w_visible) -// return -(float)(w_visible - conformed_w) / 2; - - return (float)get_xscroll(); - } - else - return ((float)-get_canvas()->get_w() / zoom_x + - edl->session->output_w) / 2; - } - else - { - int out_w, out_h; - int canvas_w = get_canvas()->get_w(); - int canvas_h = get_canvas()->get_h(); - out_w = canvas_w; - out_h = canvas_h; - - if((float)out_w / out_h > conformed_w / conformed_h) - { - out_w = (int)(out_h * conformed_w / conformed_h + 0.5); - } - - if(out_w < canvas_w) - return -(canvas_w - out_w) / 2 / zoom_x; - } - - return 0; + if( use_scrollbars ) return get_xscroll(); + int canvas_w = get_canvas()->get_w(), out_w = canvas_w; + int canvas_h = get_canvas()->get_h(), out_h = canvas_h; + float conformed_ratio = conformed_w/conformed_h; + if( (float)out_w/out_h > conformed_ratio ) + out_w = out_h * conformed_ratio + 0.5; + float ret = out_w >= canvas_w ? 0 : -0.5f*(canvas_w - out_w) / zoom_x; + return ret; } -float Canvas::get_y_offset(EDL *edl, - int single_channel, - float zoom_y, - float conformed_w, - float conformed_h) +float Canvas::get_y_offset(EDL *edl, int single_channel, + float zoom_y, float conformed_w, float conformed_h) { - if(use_scrollbars) - { - if(yscroll) - { -// If the projection is smaller than the canvas, this forces it in the center. -// if(conformed_h < h_visible) -// return -(float)(h_visible - conformed_h) / 2; - - return (float)get_yscroll(); - } - else - return ((float)-get_canvas()->get_h() / zoom_y + - edl->session->output_h) / 2; - } - else - { - int out_w, out_h; - int canvas_w = get_canvas()->get_w(); - int canvas_h = get_canvas()->get_h(); - out_w = canvas_w; - out_h = canvas_h; - - if((float)out_w / out_h <= conformed_w / conformed_h) - { - out_h = (int)((float)out_w / (conformed_w / conformed_h) + 0.5); - } - -//printf("Canvas::get_y_offset 1 %d %d %f\n", out_h, canvas_h, -((float)canvas_h - out_h) / 2); - if(out_h < canvas_h) - return -((float)canvas_h - out_h) / 2 / zoom_y; - } - - return 0; + if( use_scrollbars ) return get_yscroll(); + int canvas_w = get_canvas()->get_w(), out_w = canvas_w; + int canvas_h = get_canvas()->get_h(), out_h = canvas_h; + float conformed_ratio = conformed_w/conformed_h; + if( (float)out_w/out_h <= conformed_ratio ) + out_h = out_w / conformed_ratio + 0.5f; + float ret = out_h >= canvas_h ? 0 : -0.5f*(canvas_h - out_h) / zoom_y; + return ret; } // This may not be used anymore @@ -253,59 +193,73 @@ void Canvas::check_boundaries(EDL *edl, int &x, int &y, float &zoom) if(y < 0) y = 0; } -void Canvas::update_scrollbars(int flush) +void Canvas::update_scrollbars(EDL *edl, int flush) { - if(use_scrollbars) - { - if(xscroll) xscroll->update_length(w_needed, get_xscroll(), w_visible, flush); - if(yscroll) yscroll->update_length(h_needed, get_yscroll(), h_visible, flush); + if( edl ) + get_scrollbars(edl); + if( use_scrollbars ) { + if( xscroll ) xscroll->update_length(w_needed, get_xscroll(), w_visible, flush); + if( yscroll ) yscroll->update_length(h_needed, get_yscroll(), h_visible, flush); } } -void Canvas::get_zooms(EDL *edl, - int single_channel, - float &zoom_x, - float &zoom_y, - float &conformed_w, - float &conformed_h) +float Canvas::get_auto_zoom(EDL *edl) { - edl->calculate_conformed_dimensions(single_channel, - conformed_w, - conformed_h); + float conformed_w, conformed_h; + edl->calculate_conformed_dimensions(0, conformed_w, conformed_h); + BC_WindowBase *window = get_canvas(); + int window_w = window ? window->get_w() : w; + int window_h = window ? window->get_h() : h; + float zoom_x = window_w / conformed_w; + float zoom_y = window_h / conformed_h; + return zoom_x < zoom_y ? zoom_x : zoom_y; +} +void Canvas::zoom_auto() +{ + use_scrollbars = 0; +} - if(use_scrollbars) - { - zoom_x = get_zoom() * - conformed_w / - edl->session->output_w; - zoom_y = get_zoom() * - conformed_h / - edl->session->output_h; - } - else - { - int out_w, out_h; - int canvas_w = get_canvas()->get_w(); - int canvas_h = get_canvas()->get_h(); +void Canvas::get_zooms(EDL *edl, int single_channel, + float &zoom_x, float &zoom_y, + float &conformed_w, float &conformed_h) +{ + edl->calculate_conformed_dimensions(single_channel, + conformed_w, conformed_h); - out_w = canvas_w; - out_h = canvas_h; + float zoom = get_zoom(); + if( !use_scrollbars || !zoom ) zoom = get_auto_zoom(edl); + zoom_x = zoom * conformed_w / get_output_w(edl); + zoom_y = zoom * conformed_h / get_output_h(edl); +} - if((float)out_w / out_h > conformed_w / conformed_h) - { - out_w = (int)((float)out_h * conformed_w / conformed_h + 0.5); - } - else - { - out_h = (int)((float)out_w / (conformed_w / conformed_h) + 0.5); - } +void Canvas::set_zoom(EDL *edl, float zoom) +{ + BC_WindowBase *window = get_canvas(); + int cw = window ? window->get_w() : w; + int ch = window ? window->get_h() : h; + float cx = 0.5f * cw, cy = 0.5f * ch; + set_zoom(edl, zoom, cx, cy); +} - zoom_x = (float)out_w / edl->session->output_w; - zoom_y = (float)out_h / edl->session->output_h; -//printf("get zooms 2 %d %d %f %f\n", canvas_w, canvas_h, conformed_w, conformed_h); +void Canvas::set_zoom(EDL *edl, float zoom, float cx, float cy) +{ + float output_x = cx, output_y = cy; + canvas_to_output(edl, 0, output_x, output_y); + update_zoom(0, 0, zoom); + float zoom_x, zoom_y, conformed_w, conformed_h; + get_zooms(edl, 0, zoom_x, zoom_y, conformed_w, conformed_h); + if( zoom ) { + output_x -= cx / zoom_x; + output_y -= cy / zoom_y; + } + else { + output_x = get_x_offset(edl, 0, zoom_x, conformed_w, conformed_h); + output_y = get_y_offset(edl, 0, zoom_y, conformed_w, conformed_h); } + update_zoom(output_x, output_y, zoom); } + // Convert a coordinate on the canvas to a coordinate on the output void Canvas::canvas_to_output(EDL *edl, int single_channel, float &x, float &y) { @@ -340,245 +294,150 @@ void Canvas::get_transfers(EDL *edl, //printf("Canvas::get_transfers %d canvas_w=%d canvas_h=%d\n", // __LINE__, canvas_w, canvas_h); // automatic canvas size detection - if(canvas_w < 0) canvas_w = get_canvas()->get_w(); - if(canvas_h < 0) canvas_h = get_canvas()->get_h(); + if( canvas_w < 0 ) canvas_w = get_canvas()->get_w(); + if( canvas_h < 0 ) canvas_h = get_canvas()->get_h(); -// Canvas is zoomed to a portion of the output frame - if(use_scrollbars) - { - float in_x1, in_y1, in_x2, in_y2; - float out_x1, out_y1, out_x2, out_y2; - float zoom_x, zoom_y, conformed_w, conformed_h; - - get_zooms(edl, 0, zoom_x, zoom_y, conformed_w, conformed_h); - out_x1 = 0; - out_y1 = 0; - out_x2 = canvas_w; - out_y2 = canvas_h; - in_x1 = 0; - in_y1 = 0; - in_x2 = canvas_w; - in_y2 = canvas_h; - - canvas_to_output(edl, 0, in_x1, in_y1); - canvas_to_output(edl, 0, in_x2, in_y2); - -//printf("Canvas::get_transfers 1 %.0f %.0f %.0f %.0f -> %.0f %.0f %.0f %.0f\n", -//in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2); - - if(in_x1 < 0) - { - out_x1 += -in_x1 * zoom_x; - in_x1 = 0; - } - - if(in_y1 < 0) - { - out_y1 += -in_y1 * zoom_y; - in_y1 = 0; - } + float in_x1, in_y1, in_x2, in_y2; + float out_x1, out_y1, out_x2, out_y2; + float zoom_x, zoom_y, conformed_w, conformed_h; - int output_w = get_output_w(edl); - int output_h = get_output_h(edl); + get_zooms(edl, 0, zoom_x, zoom_y, conformed_w, conformed_h); + out_x1 = 0; out_x2 = canvas_w; + out_y1 = 0; out_y2 = canvas_h; + in_x1 = 0; in_x2 = canvas_w; + in_y1 = 0; in_y2 = canvas_h; + canvas_to_output(edl, 0, in_x1, in_y1); + canvas_to_output(edl, 0, in_x2, in_y2); - if(in_x2 > output_w) - { - out_x2 -= (in_x2 - output_w) * zoom_x; - in_x2 = output_w; - } + if( in_x1 < 0 ) { + out_x1 += -in_x1 * zoom_x; + in_x1 = 0; + } - if(in_y2 > output_h) - { - out_y2 -= (in_y2 - output_h) * zoom_y; - in_y2 = output_h; - } -// printf("Canvas::get_transfers 2 %.0f %.0f %.0f %.0f -> %.0f %.0f %.0f %.0f\n", -// in_x1, in_y1, in_x2, in_y2, out_x1, out_y1, out_x2, out_y2); - - output_x1 = in_x1; - output_y1 = in_y1; - output_x2 = in_x2; - output_y2 = in_y2; - canvas_x1 = out_x1; - canvas_y1 = out_y1; - canvas_x2 = out_x2; - canvas_y2 = out_y2; - -// Center on canvas -// if(!scrollbars_exist()) -// { -// out_x = canvas_w / 2 - out_w / 2; -// out_y = canvas_h / 2 - out_h / 2; -// } + if( in_y1 < 0 ) { + out_y1 += -in_y1 * zoom_y; + in_y1 = 0; + } + int output_w = get_output_w(edl); + int output_h = get_output_h(edl); + if( in_x2 > output_w ) { + out_x2 -= (in_x2 - output_w) * zoom_x; + in_x2 = output_w; } - else -// The output frame is normalized to the canvas - { -// Default canvas coords fill the entire canvas - canvas_x1 = 0; - canvas_y1 = 0; - canvas_x2 = canvas_w; - canvas_y2 = canvas_h; - - if(edl) - { -// Use EDL aspect ratio to shrink one of the canvas dimensions - float out_w = canvas_x2 - canvas_x1; - float out_h = canvas_y2 - canvas_y1; - if(out_w / out_h > edl->get_aspect_ratio()) - { - out_w = (int)(out_h * edl->get_aspect_ratio() + 0.5); - canvas_x1 = canvas_w / 2 - out_w / 2; - } - else - { - out_h = (int)(out_w / edl->get_aspect_ratio() + 0.5); - canvas_y1 = canvas_h / 2 - out_h / 2; -// printf("Canvas::get_transfers %d canvas_h=%d out_h=%f canvas_y1=%f\n", -// __LINE__, -// canvas_h, -// out_h, -// canvas_y1); - } - canvas_x2 = canvas_x1 + out_w; - canvas_y2 = canvas_y1 + out_h; - -// Get output frame coords from EDL - output_x1 = 0; - output_y1 = 0; - output_x2 = get_output_w(edl); - output_y2 = get_output_h(edl); - } - else -// No EDL to get aspect ratio or output frame coords from - { - output_x1 = 0; - output_y1 = 0; - output_x2 = this->output_w; - output_y2 = this->output_h; - } + + if( in_y2 > output_h ) { + out_y2 -= (in_y2 - output_h) * zoom_y; + in_y2 = output_h; } + output_x1 = in_x1; output_x2 = in_x2; + output_y1 = in_y1; output_y2 = in_y2; + canvas_x1 = out_x1; canvas_x2 = out_x2; + canvas_y1 = out_y1; canvas_y2 = out_y2; + // Clamp to minimum value - output_x1 = MAX(0, output_x1); - output_y1 = MAX(0, output_y1); - output_x2 = MAX(output_x1, output_x2); - output_y2 = MAX(output_y1, output_y2); - canvas_x1 = MAX(0, canvas_x1); - canvas_y1 = MAX(0, canvas_y1); - canvas_x2 = MAX(canvas_x1, canvas_x2); - canvas_y2 = MAX(canvas_y1, canvas_y2); -// printf("Canvas::get_transfers %d %f,%f %f,%f -> %f,%f %f,%f\n", -// __LINE__, -// output_x1, -// output_y1, -// output_x2, -// output_y2, -// canvas_x1, -// canvas_y1, -// canvas_x2, -// canvas_y2); + if( output_x1 < 0 ) output_x1 = 0; + if( output_x2 < output_x1 ) output_x2 = output_x1; + if( canvas_x1 < 0 ) canvas_x1 = 0; + if( canvas_x2 < canvas_x1 ) canvas_x2 = canvas_x1; +// printf("Canvas::get_transfers %d %f,%f %f,%f -> %f,%f %f,%f\n", __LINE__, +// output_x1, output_y1, output_x2, output_y2, +// canvas_x1, canvas_y1, canvas_x2, canvas_y2); } int Canvas::scrollbars_exist() { - return(use_scrollbars && (xscroll || yscroll)); + return use_scrollbars && (xscroll || yscroll); } int Canvas::get_output_w(EDL *edl) { - return !edl ? 0 : edl->session->output_w; + return edl->session->output_w; } int Canvas::get_output_h(EDL *edl) { - return !edl ? 0 : edl->session->output_h; + return edl->session->output_h; } - -void Canvas::get_scrollbars(EDL *edl, - int &canvas_x, - int &canvas_y, - int &canvas_w, - int &canvas_h) +int Canvas::get_scrollbars(EDL *edl) { - int need_xscroll = 0; - int need_yscroll = 0; -// int done = 0; - float zoom_x, zoom_y, conformed_w, conformed_h; + int ret = 0; + BC_WindowBase *window = get_canvas(); + if( !window ) use_scrollbars = 0; + int canvas_w = w, canvas_h = h; - if(edl) - { - w_needed = edl->session->output_w; - h_needed = edl->session->output_h; - w_visible = w_needed; - h_visible = h_needed; - } -//printf("Canvas::get_scrollbars 1 %d %d\n", get_xscroll(), get_yscroll()); + w_needed = w_visible = edl ? edl->session->output_w : view_w; + h_needed = h_visible = edl ? edl->session->output_h : view_h; - if( use_scrollbars ) { - w_needed = edl->session->output_w; - h_needed = edl->session->output_h; + int need_xscroll = 0, need_yscroll = 0; + if( edl && use_scrollbars ) { + float zoom_x, zoom_y, conformed_w, conformed_h; get_zooms(edl, 0, zoom_x, zoom_y, conformed_w, conformed_h); -//printf("Canvas::get_scrollbars 2 %d %d\n", get_xscroll(), get_yscroll()); - - w_visible = (int)(canvas_w / zoom_x); - h_visible = (int)(canvas_h / zoom_y); - if( w_needed > w_visible ) { - need_xscroll = 1; + w_visible = canvas_w / zoom_x; + h_visible = canvas_h / zoom_y; + float output_x = 0, output_y = 0; + output_to_canvas(edl, 0, output_x, output_y); + if( output_x < 0 ) need_xscroll = 1; + if( output_y < 0 ) need_yscroll = 1; + output_x = w_needed, output_y = h_needed; + output_to_canvas(edl, 0, output_x, output_y); + if( output_x > canvas_w ) need_xscroll = 1; + if( output_y > canvas_h ) need_yscroll = 1; + if( need_xscroll ) { canvas_h -= BC_ScrollBar::get_span(SCROLL_HORIZ); + h_visible = canvas_h / zoom_y; } - - if( h_needed > h_visible ) { - need_yscroll = 1; + if( need_yscroll ) { canvas_w -= BC_ScrollBar::get_span(SCROLL_VERT); + w_visible = canvas_w / zoom_x; } -//printf("Canvas::get_scrollbars %d %d %d %d %d %d\n", canvas_w, canvas_h, w_needed, h_needed, w_visible, h_visible); -//printf("Canvas::get_scrollbars 3 %d %d\n", get_xscroll(), get_yscroll()); - - w_visible = (int)(canvas_w / zoom_x); - h_visible = (int)(canvas_h / zoom_y); + view_w = canvas_w; + view_h = canvas_h; } if( need_xscroll ) { if( !xscroll ) { - xscroll = new CanvasXScroll(edl, this, canvas_x, canvas_y + canvas_h, - w_needed, get_xscroll(), w_visible, canvas_w); + xscroll = new CanvasXScroll(edl, this, view_x, view_y + view_h, + w_needed, get_xscroll(), w_visible, view_w); subwindow->add_subwindow(xscroll); xscroll->show_window(0); } else - xscroll->reposition_window(canvas_x, canvas_y + canvas_h, canvas_w); + xscroll->reposition_window(view_x, view_y + view_h, view_w); if( xscroll->get_length() != w_needed || xscroll->get_handlelength() != w_visible ) xscroll->update_length(w_needed, get_xscroll(), w_visible, 0); + ret = 1; } else if( xscroll ) { delete xscroll; xscroll = 0; + ret = 1; } -//printf("Canvas::get_scrollbars 4 %d %d\n", get_xscroll(), get_yscroll()); if( need_yscroll ) { if( !yscroll ) { - yscroll = new CanvasYScroll(edl, this, canvas_x + canvas_w, canvas_y, - h_needed, get_yscroll(), h_visible, canvas_h); + yscroll = new CanvasYScroll(edl, this, view_x + view_w, view_y, + h_needed, get_yscroll(), h_visible, view_h); subwindow->add_subwindow(yscroll); yscroll->show_window(0); } else - yscroll->reposition_window(canvas_x + canvas_w, canvas_y, canvas_h); + yscroll->reposition_window(view_x + view_w, view_y, view_h); if( yscroll->get_length() != edl->session->output_h || yscroll->get_handlelength() != h_visible ) yscroll->update_length(h_needed, get_yscroll(), h_visible, 0); + ret = 1; } else if( yscroll ) { delete yscroll; yscroll = 0; + ret = 1; } -//printf("Canvas::get_scrollbars 5 %d %d\n", get_xscroll(), get_yscroll()); + return ret; } @@ -586,15 +445,12 @@ void Canvas::update_geometry(EDL *edl, int x, int y, int w, int h) { int redraw = 0; if( this->x != x || this->y != y || - this->w != w || this->h != h ) redraw = 1; - if( !redraw ) { - int vx = x, vy = y, vw = w, vh = h; - get_scrollbars(edl, vx, vy, vw, vh); - if( vx != view_x || vy != view_y || - vw != view_w || vh != view_h ) redraw = 1; - } - if( !redraw ) return; - reposition_window(edl, x, y, w, h); + this->w != w || this->h != h ) + redraw = 1; + if( !redraw ) + redraw = get_scrollbars(edl); + if( redraw ) + reposition_window(edl, x, y, w, h); } void Canvas::reposition_window(EDL *edl, int x, int y, int w, int h) @@ -602,20 +458,14 @@ void Canvas::reposition_window(EDL *edl, int x, int y, int w, int h) this->x = view_x = x; this->y = view_y = y; this->w = view_w = w; this->h = view_h = h; //printf("Canvas::reposition_window 1\n"); - get_scrollbars(edl, view_x, view_y, view_w, view_h); + get_scrollbars(edl); //printf("Canvas::reposition_window %d %d %d %d\n", view_x, view_y, view_w, view_h); - if(canvas_subwindow) - { + if( canvas_subwindow ) { canvas_subwindow->reposition_window(view_x, view_y, view_w, view_h); // Need to clear out the garbage in the back - if(canvas_subwindow->get_video_on()) - { - canvas_subwindow->set_color(BLACK); - canvas_subwindow->draw_box(0, 0, - get_canvas()->get_w(), get_canvas()->get_h()); - canvas_subwindow->flash(0); - } + if( canvas_subwindow->get_video_on() ) + clear_borders(edl); } refresh(0); } @@ -664,11 +514,9 @@ int Canvas::get_buttonpress() void Canvas::create_objects(EDL *edl) { - view_x = x; - view_y = y; - view_w = w; - view_h = h; - get_scrollbars(edl, view_x, view_y, view_w, view_h); + view_x = x; view_y = y; + view_w = w; view_h = h; + get_scrollbars(edl); subwindow->unlock_window(); create_canvas(); @@ -729,6 +577,19 @@ void Canvas::stop_video() } +int Canvas::use_fullscreen(int on) +{ + if( on && !get_fullscreen() ) { + start_fullscreen(); + return 1; + } + if( !on && get_fullscreen() ) { + stop_fullscreen(); + return 1; + } + return 0; +} + void Canvas::start_fullscreen() { set_fullscreen(1); @@ -789,10 +650,11 @@ void Canvas::create_canvas() wdw->reposition_window(x, y); } - if( !video_on ) - draw_refresh(1); - else + if( video_on ) wdw->start_video(); + else + draw_refresh(1); + wdw->focus(); wdw->unlock_window(); canvas_lock->unlock(); @@ -834,16 +696,12 @@ int Canvas::keypress_event(BC_WindowBase *caller) switch( key ) { case 'f': caller->unlock_window(); - if(get_fullscreen()) - stop_fullscreen(); - else - start_fullscreen(); + use_fullscreen(get_fullscreen() ? 0 : 1); caller->lock_window("Canvas::keypress_event 1"); break; case ESC: caller->unlock_window(); - if(get_fullscreen()) - stop_fullscreen(); + use_fullscreen(0); caller->lock_window("Canvas::keypress_event 2"); break; default: @@ -1017,7 +875,8 @@ CanvasXScroll::~CanvasXScroll() int CanvasXScroll::handle_event() { - canvas->update_zoom(get_value(), canvas->get_yscroll(), canvas->get_zoom()); + canvas->update_zoom(get_value(), canvas->get_yscroll(), + canvas->get_zoom()); return canvas->refresh(1); } @@ -1035,7 +894,8 @@ CanvasYScroll::~CanvasYScroll() int CanvasYScroll::handle_event() { - canvas->update_zoom(canvas->get_xscroll(), get_value(), canvas->get_zoom()); + canvas->update_zoom(canvas->get_xscroll(), get_value(), + canvas->get_zoom()); return canvas->refresh(1); } @@ -1068,7 +928,7 @@ int CanvasSubWindowItem::handle_event() // It isn't a problem to delete the canvas from in here because the event // dispatcher is the canvas subwindow. canvas->subwindow->unlock_window(); - canvas->stop_fullscreen(); + canvas->use_fullscreen(0); canvas->subwindow->lock_window("CanvasSubWindowItem::handle_event"); return 1; } @@ -1262,7 +1122,7 @@ CanvasFullScreenItem::CanvasFullScreenItem(Canvas *canvas) int CanvasFullScreenItem::handle_event() { canvas->subwindow->unlock_window(); - canvas->start_fullscreen(); + canvas->use_fullscreen(1); canvas->subwindow->lock_window("CanvasFullScreenItem::handle_event"); return 1; } diff --git a/cinelerra-5.1/cinelerra/canvas.h b/cinelerra-5.1/cinelerra/canvas.h index 8d30dccc..140f70f2 100644 --- a/cinelerra-5.1/cinelerra/canvas.h +++ b/cinelerra-5.1/cinelerra/canvas.h @@ -58,24 +58,17 @@ public: void start_single(); void stop_single(); - void start_fullscreen(); - void stop_fullscreen(); - // Don't call from inside the canvas void create_canvas(); - - // Processing or video playback changed. virtual void status_event() {}; - virtual void reset_camera() {} virtual void reset_projector() {} virtual void camera_keyframe() {} virtual void projector_keyframe() {} virtual void zoom_resize_window(float percentage) {} - virtual void zoom_auto() {} virtual int cursor_leave_event() { return 0; } virtual int cursor_enter_event() { return 0; } virtual int button_release_event() { return 0; } @@ -86,8 +79,9 @@ public: virtual void toggle_controls() {} virtual int get_cwindow_controls() { return 0; } virtual int get_fullscreen(); - virtual int get_clear_color(); virtual void set_fullscreen(int value); + virtual int get_clear_color(); + virtual int use_fullscreen(int on); int cursor_leave_event_base(BC_WindowBase *caller); int cursor_enter_event_base(BC_WindowBase *caller); @@ -121,15 +115,17 @@ public: virtual void reset_translation() {}; virtual void close_source() {}; // Updates the stores - virtual void update_zoom(int x, int y, float zoom) {}; + virtual void update_zoom(int x, int y, float zoom) {} void check_boundaries(EDL *edl, int &x, int &y, float &zoom); void clear_borders(EDL *edl); - void update_scrollbars(int flush); + void update_scrollbars(EDL *edl, int flush); // Get scrollbar positions relative to output. // No correction is done if output is smaller than canvas - virtual int get_xscroll() { return 0; }; - virtual int get_yscroll() { return 0; }; - virtual float get_zoom() { return 0; }; + virtual int get_xscroll() { return 0; } + virtual int get_yscroll() { return 0; } + virtual float get_zoom() { return 0; } + virtual float get_auto_zoom(EDL *edl); + virtual void zoom_auto(); // Updates the refresh_frame void update_refresh(VideoDevice *device, VFrame *output_frame); // Redraws the refresh_frame @@ -138,23 +134,16 @@ public: // Get top left offset of canvas relative to output. // Normally negative. Can be positive if output is smaller than canvas. - float get_x_offset(EDL *edl, - int single_channel, - float zoom_x, - float conformed_w, - float conformed_h); - float get_y_offset(EDL *edl, - int single_channel, - float zoom_y, - float conformed_w, - float conformed_h); - void get_zooms(EDL *edl, - int single_channel, - float &zoom_x, - float &zoom_y, - float &conformed_w, - float &conformed_h); + float get_x_offset(EDL *edl, int single_channel, float zoom_x, + float conformed_w, float conformed_h); + float get_y_offset(EDL *edl, int single_channel, float zoom_y, + float conformed_w, float conformed_h); + void get_zooms(EDL *edl, int single_channel, + float &zoom_x, float &zoom_y, + float &conformed_w, float &conformed_h); + void set_zoom(EDL *edl, float zoom); + void set_zoom(EDL *edl, float zoom, float cx, float cy); // Convert coord from output to canvas position, including // x and y scroll offsets @@ -196,28 +185,25 @@ public: // refreshes. VFrame *refresh_frame; // Results from last get_scrollbars - int w_needed; - int h_needed; - int w_visible; - int h_visible; + int w_needed, h_needed; + int w_visible, h_visible; // For cases where video is not enabled on the canvas but processing is // occurring for a single frame, this causes the status to update. int is_processing; int is_fullscreen; // Cursor is inside video surface int cursor_inside; - int view_x; - int view_y; - int view_w; - int view_h; - int scr_w0; + int view_x, view_y, view_w, view_h; int root_w, root_h; + int scr_w0; MWindow *mwindow; private: - void get_scrollbars(EDL *edl, - int &canvas_x, int &canvas_y, int &canvas_w, int &canvas_h); + int get_scrollbars(EDL *edl); + void start_fullscreen(); + void stop_fullscreen(); + // Lock access to the canvas pointer. Condition *canvas_lock; }; diff --git a/cinelerra-5.1/cinelerra/cpanel.C b/cinelerra-5.1/cinelerra/cpanel.C index fa440711..4099397e 100644 --- a/cinelerra-5.1/cinelerra/cpanel.C +++ b/cinelerra-5.1/cinelerra/cpanel.C @@ -387,7 +387,8 @@ int CPanelZoom::handle_event() double zoom = pow(10.,value); switch( mwindow->edl->session->cwindow_operation ) { case CWINDOW_ZOOM: - gui->subwindow->zoom_canvas(zoom, 1); + gui->subwindow->canvas->set_zoom(mwindow->edl, zoom); + gui->subwindow->update_canvas(); break; case CWINDOW_CAMERA: aidx = AUTOMATION_CAMERA_Z; diff --git a/cinelerra-5.1/cinelerra/cwindow.C b/cinelerra-5.1/cinelerra/cwindow.C index d6061758..d4047e35 100644 --- a/cinelerra-5.1/cinelerra/cwindow.C +++ b/cinelerra-5.1/cinelerra/cwindow.C @@ -228,7 +228,7 @@ void CWindow::update(int dir, int overlays, int tool_window, int operation, int gui->timebar->update(1); double zoom = !mwindow->edl->session->cwindow_scrollbars ? - 0 :mwindow->edl->session->cwindow_zoom; + 0 : mwindow->edl->session->cwindow_zoom; gui->zoom_panel->update(zoom); gui->canvas->update_zoom(mwindow->edl->session->cwindow_xscroll, @@ -328,10 +328,7 @@ int CWindowRemoteHandler::remote_process_key(RemoteControl *remote_control, int break; case 'f': { Canvas *canvas = mwindow_gui->mwindow->cwindow->gui->canvas; - if( !canvas->get_fullscreen() ) - canvas->start_fullscreen(); - else - canvas->stop_fullscreen(); + canvas->use_fullscreen(canvas->get_fullscreen() ? 0 : 1); return 1; } default: return -1; diff --git a/cinelerra-5.1/cinelerra/cwindowgui.C b/cinelerra-5.1/cinelerra/cwindowgui.C index ebc6997e..1266f241 100644 --- a/cinelerra-5.1/cinelerra/cwindowgui.C +++ b/cinelerra-5.1/cinelerra/cwindowgui.C @@ -77,7 +77,7 @@ static int total_zooms = sizeof(my_zoom_table) / sizeof(double); CWindowGUI::CWindowGUI(MWindow *mwindow, CWindow *cwindow) : BC_Window(_(PROGRAM_NAME ": Compositor"), - mwindow->session->cwindow_x, + mwindow->session->cwindow_x, mwindow->session->cwindow_y, mwindow->session->cwindow_w, mwindow->session->cwindow_h, @@ -116,13 +116,13 @@ CWindowGUI::CWindowGUI(MWindow *mwindow, CWindow *cwindow) CWindowGUI::~CWindowGUI() { cwindow->stop_playback(1); - if(tool_panel) delete tool_panel; - delete meters; - delete composite_panel; - delete canvas; - delete transport; - delete edit_panel; - delete zoom_panel; + if( tool_panel ) delete tool_panel; + delete meters; + delete composite_panel; + delete canvas; + delete transport; + delete edit_panel; + delete zoom_panel; delete active; delete inactive; delete focus_frame; @@ -174,11 +174,11 @@ void CWindowGUI::create_objects() timebar->create_objects(); #ifdef USE_SLIDER - add_subwindow(slider = new CWindowSlider(mwindow, - cwindow, + add_subwindow(slider = new CWindowSlider(mwindow, + cwindow, mwindow->theme->cslider_x, - mwindow->theme->cslider_y, - mwindow->theme->cslider_w)); + mwindow->theme->cslider_y, + mwindow->theme->cslider_w)); #endif transport = new CWindowTransport(mwindow, @@ -238,18 +238,15 @@ int CWindowGUI::resize_event(int w, int h) composite_panel->reposition_buttons(mwindow->theme->ccomposite_x, mwindow->theme->ccomposite_y, mwindow->theme->ccomposite_h); - canvas->reposition_window(mwindow->edl, - mwindow->theme->ccanvas_x, - mwindow->theme->ccanvas_y, - mwindow->theme->ccanvas_w, - mwindow->theme->ccanvas_h); + canvas->set_zoom(mwindow->edl, canvas->get_zoom()); + update_canvas(); timebar->resize_event(); #ifdef USE_SLIDER - slider->reposition_window(mwindow->theme->cslider_x, - mwindow->theme->cslider_y, - mwindow->theme->cslider_w); + slider->reposition_window(mwindow->theme->cslider_x, + mwindow->theme->cslider_y, + mwindow->theme->cslider_w); // Recalibrate pointer motion range slider->set_position(); #endif @@ -308,36 +305,35 @@ int CWindowGUI::button_press_event() return transport->frame_reverse_play->handle_event(); } } - if(canvas->get_canvas()) + if( canvas->get_canvas() ) return canvas->button_press_event_base(canvas->get_canvas()); return 0; } int CWindowGUI::cursor_leave_event() { - if(canvas->get_canvas()) + if( canvas->get_canvas() ) return canvas->cursor_leave_event_base(canvas->get_canvas()); return 0; } int CWindowGUI::cursor_enter_event() { - if(canvas->get_canvas()) + if( canvas->get_canvas() ) return canvas->cursor_enter_event_base(canvas->get_canvas()); return 0; } int CWindowGUI::button_release_event() { - if(canvas->get_canvas()) + if( canvas->get_canvas() ) return canvas->button_release_event(); return 0; } int CWindowGUI::cursor_motion_event() { - if(canvas->get_canvas()) - { + if( canvas->get_canvas() ) { canvas->get_canvas()->unhide_cursor(); return canvas->cursor_motion_event(); } @@ -353,14 +349,12 @@ int CWindowGUI::cursor_motion_event() void CWindowGUI::draw_status(int flush) { if( (canvas->get_canvas() && canvas->get_canvas()->get_video_on()) || - canvas->is_processing ) - { + canvas->is_processing ) { draw_pixmap(active, mwindow->theme->cstatus_x, mwindow->theme->cstatus_y); } - else - { + else { draw_pixmap(inactive, mwindow->theme->cstatus_x, mwindow->theme->cstatus_y); @@ -376,43 +370,20 @@ void CWindowGUI::draw_status(int flush) flush); } -float CWindowGUI::get_auto_zoom() -{ - float conformed_w, conformed_h; - mwindow->edl->calculate_conformed_dimensions(0, conformed_w, conformed_h); - float zoom_x = canvas->w / conformed_w; - float zoom_y = canvas->h / conformed_h; - return zoom_x < zoom_y ? zoom_x : zoom_y; -} - -void CWindowGUI::zoom_canvas(double value, int update_menu) +void CWindowGUI::update_canvas(int redraw) { - float x = 0, y = 0; - float zoom = !value ? get_auto_zoom() : value; - EDL *edl = mwindow->edl; - edl->session->cwindow_scrollbars = !value ? 0 : 1; - if( value ) { - float cx = 0.5f * canvas->w; x = cx; - float cy = 0.5f * canvas->h; y = cy; - canvas->canvas_to_output(edl, 0, x, y); - canvas->update_zoom(0, 0, zoom); - float zoom_x, zoom_y, conformed_w, conformed_h; - canvas->get_zooms(edl, 0, zoom_x, zoom_y, conformed_w, conformed_h); - x -= cx / zoom_x; - y -= cy / zoom_y; - - } - canvas->update_zoom((int)(x+0.5), (int)(y+0.5), zoom); - - if( update_menu ) - zoom_panel->update(value); - if( mwindow->edl->session->cwindow_operation == CWINDOW_ZOOM ) + float zoom = canvas->get_zoom(); + zoom_panel->update(zoom); + if( mwindow->edl->session->cwindow_operation == CWINDOW_ZOOM ) { + if( !zoom ) zoom = canvas->get_auto_zoom(mwindow->edl); composite_panel->cpanel_zoom->update(zoom); - + } + canvas->update_scrollbars(mwindow->edl, 0); canvas->reposition_window(mwindow->edl, mwindow->theme->ccanvas_x, mwindow->theme->ccanvas_y, mwindow->theme->ccanvas_w, mwindow->theme->ccanvas_h); - canvas->refresh(0); + if( redraw ) + canvas->refresh(0); } void CWindowGUI::set_operation(int value) @@ -473,10 +444,7 @@ int CWindowGUI::keypress_event() break; case 'f': unlock_window(); - if( canvas->get_fullscreen() ) - canvas->stop_fullscreen(); - else - canvas->start_fullscreen(); + canvas->use_fullscreen(canvas->get_fullscreen() ? 0 : 1); lock_window("CWindowGUI::keypress_event 1"); result = 1; break; @@ -499,8 +467,7 @@ int CWindowGUI::keypress_event() break; case ESC: unlock_window(); - if( canvas->get_fullscreen() ) - canvas->stop_fullscreen(); + canvas->use_fullscreen(0); lock_window("CWindowGUI::keypress_event 4"); result = 1; break; @@ -517,7 +484,7 @@ int CWindowGUI::keypress_event() mwindow->move_left(); mwindow->gui->unlock_window(); lock_window("CWindowGUI::keypress_event 6"); - result = 1; + result = 1; } break; @@ -641,24 +608,12 @@ void CWindowGUI::reset_affected() void CWindowGUI::keyboard_zoomin() { -// if(mwindow->edl->session->cwindow_scrollbars) -// { - zoom_panel->zoom_tumbler->handle_up_event(); -// } -// else -// { -// } + zoom_panel->zoom_tumbler->handle_up_event(); } void CWindowGUI::keyboard_zoomout() { -// if(mwindow->edl->session->cwindow_scrollbars) -// { - zoom_panel->zoom_tumbler->handle_down_event(); -// } -// else -// { -// } + zoom_panel->zoom_tumbler->handle_down_event(); } void CWindowGUI::sync_parameters(int change_type, int redraw, int overlay) @@ -683,11 +638,11 @@ void CWindowGUI::sync_parameters(int change_type, int redraw, int overlay) void CWindowGUI::drag_motion() { - if(get_hidden()) return; + if( get_hidden() ) return; - if(mwindow->session->current_operation != DRAG_ASSET && + if( mwindow->session->current_operation != DRAG_ASSET && mwindow->session->current_operation != DRAG_VTRANSITION && - mwindow->session->current_operation != DRAG_VEFFECT) return; + mwindow->session->current_operation != DRAG_VEFFECT ) return; int need_highlight = cursor_above() && get_cursor_over_window(); if( highlighted == need_highlight ) return; highlighted = need_highlight; @@ -697,7 +652,7 @@ void CWindowGUI::drag_motion() int CWindowGUI::drag_stop() { int result = 0; - if(get_hidden()) return 0; + if( get_hidden() ) return 0; if( !highlighted ) return 0; if( mwindow->session->current_operation != DRAG_ASSET && mwindow->session->current_operation != DRAG_VTRANSITION && @@ -706,17 +661,14 @@ int CWindowGUI::drag_stop() canvas->refresh(1); result = 1; - if(mwindow->session->current_operation == DRAG_ASSET) - { - if(mwindow->session->drag_assets->total || - mwindow->session->drag_clips->total) - { + if( mwindow->session->current_operation == DRAG_ASSET ) { + if( mwindow->session->drag_assets->total || + mwindow->session->drag_clips->total ) { mwindow->gui->lock_window("CWindowGUI::drag_stop 1"); mwindow->undo->update_undo_before(_("insert assets"), 0); } - if(mwindow->session->drag_assets->total) - { + if( mwindow->session->drag_assets->total ) { mwindow->clear(0); mwindow->load_assets(mwindow->session->drag_assets, mwindow->edl->local_session->get_selectionstart(), @@ -729,8 +681,7 @@ int CWindowGUI::drag_stop() 0); // overwrite } - if(mwindow->session->drag_clips->total) - { + if( mwindow->session->drag_clips->total ) { mwindow->clear(0); mwindow->paste_edls(mwindow->session->drag_clips, LOADMODE_PASTE, @@ -742,9 +693,8 @@ int CWindowGUI::drag_stop() 0); // overwrite } - if(mwindow->session->drag_assets->total || - mwindow->session->drag_clips->total) - { + if( mwindow->session->drag_assets->total || + mwindow->session->drag_clips->total ) { mwindow->save_backup(); mwindow->restart_brender(); mwindow->gui->update(1, NORMAL_DRAW, 1, 1, 0, 1, 0); @@ -754,8 +704,7 @@ int CWindowGUI::drag_stop() } } - if(mwindow->session->current_operation == DRAG_VEFFECT) - { + if( mwindow->session->current_operation == DRAG_VEFFECT ) { //printf("CWindowGUI::drag_stop 1\n"); Track *affected_track = cwindow->calculate_affected_track(); //printf("CWindowGUI::drag_stop 2\n"); @@ -766,8 +715,7 @@ int CWindowGUI::drag_stop() mwindow->gui->unlock_window(); } - if(mwindow->session->current_operation == DRAG_VTRANSITION) - { + if( mwindow->session->current_operation == DRAG_VTRANSITION ) { Track *affected_track = cwindow->calculate_affected_track(); mwindow->gui->lock_window("CWindowGUI::drag_stop 4"); mwindow->paste_transition_cwindow(affected_track); @@ -780,8 +728,7 @@ int CWindowGUI::drag_stop() void CWindowGUI::update_meters() { - if(mwindow->edl->session->cwindow_meter != meters->visible) - { + if( mwindow->edl->session->cwindow_meter != meters->visible ) { meters->set_meters(meters->meter_count, mwindow->edl->session->cwindow_meter); mwindow->theme->get_cwindow_sizes(this, mwindow->session->cwindow_controls); resize_event(get_w(), get_h()); @@ -938,7 +885,8 @@ void CWindowZoom::update(double value) int CWindowZoom::handle_event() { double value = !strcasecmp(gui->auto_zoom, get_text()) ? 0 : get_value(); - gui->zoom_canvas(value, 0); + gui->canvas->set_zoom(mwindow->edl, value); + gui->update_canvas(); return 1; } @@ -1045,16 +993,22 @@ void CWindowCanvas::status_event() void CWindowCanvas::update_zoom(int x, int y, float zoom) { - use_scrollbars = mwindow->edl->session->cwindow_scrollbars; - mwindow->edl->session->cwindow_xscroll = x; mwindow->edl->session->cwindow_yscroll = y; mwindow->edl->session->cwindow_zoom = zoom; + use_scrollbars = !zoom ? 0 : 1; + mwindow->edl->session->cwindow_scrollbars = use_scrollbars; } -void CWindowCanvas::zoom_auto() +int CWindowCanvas::use_fullscreen(int on) { - gui->zoom_canvas(0, 1); + if( Canvas::use_fullscreen(on) ) { + gui->lock_window("CWindowCanvas::use_fullscreen"); + zoom_auto(); + if( !on ) gui->zoom_panel->update(0); + gui->unlock_window(); + } + return 1; } int CWindowCanvas::get_xscroll() @@ -1073,6 +1027,32 @@ float CWindowCanvas::get_zoom() return mwindow->edl->session->cwindow_zoom; } +void CWindowCanvas::zoom_auto() +{ + use_scrollbars = 0; + set_zoom(mwindow->edl, 0); + gui->update_canvas(); +} + +int CWindowCanvas::do_scroll(EDL *edl, float cursor_x, float cursor_y) +{ + float zoom = get_zoom(); + float zoom_x, zoom_y, conformed_w, conformed_h; + get_zooms(edl, 0, zoom_x, zoom_y, conformed_w, conformed_h); + if( !zoom ) { + x = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h); + y = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h); + zoom = get_auto_zoom(mwindow->edl); + } + else { + x = gui->x_origin - cursor_x / zoom_x; + y = gui->y_origin - cursor_y / zoom_y; + } + update_zoom(x, y, zoom); + gui->update_canvas(); + return 1; +} + void CWindowCanvas::draw_refresh(int flush) { BC_WindowBase *window = get_canvas(); @@ -1143,10 +1123,11 @@ int CWindowCanvas::do_ruler(int draw, int motion, int button_press, int button_release) { int result = 0; - float x1 = mwindow->edl->session->ruler_x1; - float y1 = mwindow->edl->session->ruler_y1; - float x2 = mwindow->edl->session->ruler_x2; - float y2 = mwindow->edl->session->ruler_y2; + EDLSession *session = mwindow->edl->session; + float x1 = session->ruler_x1; + float y1 = session->ruler_y1; + float x2 = session->ruler_x2; + float y2 = session->ruler_y2; float canvas_x1 = x1; float canvas_y1 = y1; float canvas_x2 = x2; @@ -1162,32 +1143,28 @@ int CWindowCanvas::do_ruler(int draw, int motion, mwindow->session->cwindow_output_x = roundf(output_x); mwindow->session->cwindow_output_y = roundf(output_y); - if(button_press && get_buttonpress() == 1) - { + if( button_press && get_buttonpress() == 1 ) { gui->ruler_handle = -1; gui->ruler_translate = 0; - if(gui->alt_down()) - { + if( gui->alt_down() ) { gui->ruler_translate = 1; gui->ruler_origin_x = x1; gui->ruler_origin_y = y1; } else - if(canvas_cursor_x >= canvas_x1 - RULERHANDLE_W / 2 && + if( canvas_cursor_x >= canvas_x1 - RULERHANDLE_W / 2 && canvas_cursor_x < canvas_x1 + RULERHANDLE_W / 2 && canvas_cursor_y >= canvas_y1 - RULERHANDLE_W && - canvas_cursor_y < canvas_y1 + RULERHANDLE_H / 2) - { + canvas_cursor_y < canvas_y1 + RULERHANDLE_H / 2 ) { gui->ruler_handle = 0; gui->ruler_origin_x = x1; gui->ruler_origin_y = y1; } else - if(canvas_cursor_x >= canvas_x2 - RULERHANDLE_W / 2 && + if( canvas_cursor_x >= canvas_x2 - RULERHANDLE_W / 2 && canvas_cursor_x < canvas_x2 + RULERHANDLE_W / 2 && canvas_cursor_y >= canvas_y2 - RULERHANDLE_W && - canvas_cursor_y < canvas_y2 + RULERHANDLE_H / 2) - { + canvas_cursor_y < canvas_y2 + RULERHANDLE_H / 2 ) { gui->ruler_handle = 1; gui->ruler_origin_x = x2; gui->ruler_origin_y = y2; @@ -1195,21 +1172,20 @@ int CWindowCanvas::do_ruler(int draw, int motion, // Start new selection - if(!gui->ruler_translate && + if( !gui->ruler_translate && (gui->ruler_handle < 0 || (EQUIV(x2, x1) && - EQUIV(y2, y1)))) - { + EQUIV(y2, y1))) ) { // Hide previous do_ruler(1, 0, 0, 0); get_canvas()->flash(); gui->ruler_handle = 1; - mwindow->edl->session->ruler_x1 = output_x; - mwindow->edl->session->ruler_y1 = output_y; - mwindow->edl->session->ruler_x2 = output_x; - mwindow->edl->session->ruler_y2 = output_y; - gui->ruler_origin_x = mwindow->edl->session->ruler_x2; - gui->ruler_origin_y = mwindow->edl->session->ruler_y2; + session->ruler_x1 = output_x; + session->ruler_y1 = output_y; + session->ruler_x2 = output_x; + session->ruler_y2 = output_y; + gui->ruler_origin_x = session->ruler_x2; + gui->ruler_origin_y = session->ruler_y2; } gui->x_origin = output_x; @@ -1219,71 +1195,62 @@ int CWindowCanvas::do_ruler(int draw, int motion, result = 1; } - if(motion) - { - if(gui->current_operation == CWINDOW_RULER) - { - if(gui->ruler_translate) - { + if( motion ) { + if( gui->current_operation == CWINDOW_RULER ) { + if( gui->ruler_translate ) { // Hide ruler do_ruler(1, 0, 0, 0); - float x_difference = mwindow->edl->session->ruler_x1; - float y_difference = mwindow->edl->session->ruler_y1; - mwindow->edl->session->ruler_x1 = output_x - gui->x_origin + gui->ruler_origin_x; - mwindow->edl->session->ruler_y1 = output_y - gui->y_origin + gui->ruler_origin_y; - x_difference -= mwindow->edl->session->ruler_x1; - y_difference -= mwindow->edl->session->ruler_y1; - mwindow->edl->session->ruler_x2 -= x_difference; - mwindow->edl->session->ruler_y2 -= y_difference; + float x_difference = session->ruler_x1; + float y_difference = session->ruler_y1; + session->ruler_x1 = output_x - gui->x_origin + gui->ruler_origin_x; + session->ruler_y1 = output_y - gui->y_origin + gui->ruler_origin_y; + x_difference -= session->ruler_x1; + y_difference -= session->ruler_y1; + session->ruler_x2 -= x_difference; + session->ruler_y2 -= y_difference; // Show ruler do_ruler(1, 0, 0, 0); get_canvas()->flash(); gui->update_tool(); } - else - switch(gui->ruler_handle) - { + else { + switch( gui->ruler_handle ) { case 0: do_ruler(1, 0, 0, 0); - mwindow->edl->session->ruler_x1 = output_x - gui->x_origin + gui->ruler_origin_x; - mwindow->edl->session->ruler_y1 = output_y - gui->y_origin + gui->ruler_origin_y; - if(gui->alt_down() || gui->ctrl_down()) - { - double angle_value = fabs(atan((mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1) / - (mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1)) * + session->ruler_x1 = output_x - gui->x_origin + gui->ruler_origin_x; + session->ruler_y1 = output_y - gui->y_origin + gui->ruler_origin_y; + if( gui->alt_down() || gui->ctrl_down() ) { + double angle_value = fabs(atan((session->ruler_y2 - session->ruler_y1) / + (session->ruler_x2 - session->ruler_x1)) * 360 / 2 / M_PI); double distance_value = - sqrt(SQR(mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1) + - SQR(mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1)); - if(angle_value < 22) - mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2; + sqrt(SQR(session->ruler_x2 - session->ruler_x1) + + SQR(session->ruler_y2 - session->ruler_y1)); + if( angle_value < 22 ) + session->ruler_y1 = session->ruler_y2; else - if(angle_value > 67) - mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2; + if( angle_value > 67 ) + session->ruler_x1 = session->ruler_x2; else - if(mwindow->edl->session->ruler_x1 < mwindow->edl->session->ruler_x2 && - mwindow->edl->session->ruler_y1 < mwindow->edl->session->ruler_y2) - { - mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 - distance_value / 1.414214; - mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 - distance_value / 1.414214; + if( session->ruler_x1 < session->ruler_x2 && + session->ruler_y1 < session->ruler_y2 ) { + session->ruler_x1 = session->ruler_x2 - distance_value / 1.414214; + session->ruler_y1 = session->ruler_y2 - distance_value / 1.414214; } else - if(mwindow->edl->session->ruler_x1 < mwindow->edl->session->ruler_x2 && mwindow->edl->session->ruler_y1 > mwindow->edl->session->ruler_y2) - { - mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 - distance_value / 1.414214; - mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 + distance_value / 1.414214; + if( session->ruler_x1 < session->ruler_x2 && session->ruler_y1 > session->ruler_y2 ) { + session->ruler_x1 = session->ruler_x2 - distance_value / 1.414214; + session->ruler_y1 = session->ruler_y2 + distance_value / 1.414214; } else - if(mwindow->edl->session->ruler_x1 > mwindow->edl->session->ruler_x2 && - mwindow->edl->session->ruler_y1 < mwindow->edl->session->ruler_y2) - { - mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 + distance_value / 1.414214; - mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 - distance_value / 1.414214; + if( session->ruler_x1 > session->ruler_x2 && + session->ruler_y1 < session->ruler_y2 ) { + session->ruler_x1 = session->ruler_x2 + distance_value / 1.414214; + session->ruler_y1 = session->ruler_y2 - distance_value / 1.414214; } - else - { - mwindow->edl->session->ruler_x1 = mwindow->edl->session->ruler_x2 + distance_value / 1.414214; - mwindow->edl->session->ruler_y1 = mwindow->edl->session->ruler_y2 + distance_value / 1.414214; + else { + session->ruler_x1 = session->ruler_x2 + distance_value / 1.414214; + session->ruler_y1 = session->ruler_y2 + distance_value / 1.414214; } } do_ruler(1, 0, 0, 0); @@ -1293,74 +1260,67 @@ int CWindowCanvas::do_ruler(int draw, int motion, case 1: do_ruler(1, 0, 0, 0); - mwindow->edl->session->ruler_x2 = output_x - gui->x_origin + gui->ruler_origin_x; - mwindow->edl->session->ruler_y2 = output_y - gui->y_origin + gui->ruler_origin_y; - if(gui->alt_down() || gui->ctrl_down()) - { - double angle_value = fabs(atan((mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1) / - (mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1)) * + session->ruler_x2 = output_x - gui->x_origin + gui->ruler_origin_x; + session->ruler_y2 = output_y - gui->y_origin + gui->ruler_origin_y; + if( gui->alt_down() || gui->ctrl_down() ) { + double angle_value = fabs(atan((session->ruler_y2 - session->ruler_y1) / + (session->ruler_x2 - session->ruler_x1)) * 360 / 2 / M_PI); double distance_value = - sqrt(SQR(mwindow->edl->session->ruler_x2 - mwindow->edl->session->ruler_x1) + - SQR(mwindow->edl->session->ruler_y2 - mwindow->edl->session->ruler_y1)); - if(angle_value < 22) - mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1; + sqrt(SQR(session->ruler_x2 - session->ruler_x1) + + SQR(session->ruler_y2 - session->ruler_y1)); + if( angle_value < 22 ) + session->ruler_y2 = session->ruler_y1; else - if(angle_value > 67) - mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1; + if( angle_value > 67 ) + session->ruler_x2 = session->ruler_x1; else - if(mwindow->edl->session->ruler_x2 < mwindow->edl->session->ruler_x1 && - mwindow->edl->session->ruler_y2 < mwindow->edl->session->ruler_y1) - { - mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 - distance_value / 1.414214; - mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 - distance_value / 1.414214; + if( session->ruler_x2 < session->ruler_x1 && + session->ruler_y2 < session->ruler_y1 ) { + session->ruler_x2 = session->ruler_x1 - distance_value / 1.414214; + session->ruler_y2 = session->ruler_y1 - distance_value / 1.414214; } else - if(mwindow->edl->session->ruler_x2 < mwindow->edl->session->ruler_x1 && - mwindow->edl->session->ruler_y2 > mwindow->edl->session->ruler_y1) - { - mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 - distance_value / 1.414214; - mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 + distance_value / 1.414214; + if( session->ruler_x2 < session->ruler_x1 && + session->ruler_y2 > session->ruler_y1 ) { + session->ruler_x2 = session->ruler_x1 - distance_value / 1.414214; + session->ruler_y2 = session->ruler_y1 + distance_value / 1.414214; } else - if(mwindow->edl->session->ruler_x2 > mwindow->edl->session->ruler_x1 && mwindow->edl->session->ruler_y2 < mwindow->edl->session->ruler_y1) - { - mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 + distance_value / 1.414214; - mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 - distance_value / 1.414214; + if( session->ruler_x2 > session->ruler_x1 && session->ruler_y2 < session->ruler_y1 ) { + session->ruler_x2 = session->ruler_x1 + distance_value / 1.414214; + session->ruler_y2 = session->ruler_y1 - distance_value / 1.414214; } - else - { - mwindow->edl->session->ruler_x2 = mwindow->edl->session->ruler_x1 + distance_value / 1.414214; - mwindow->edl->session->ruler_y2 = mwindow->edl->session->ruler_y1 + distance_value / 1.414214; + else { + session->ruler_x2 = session->ruler_x1 + distance_value / 1.414214; + session->ruler_y2 = session->ruler_y1 + distance_value / 1.414214; } } do_ruler(1, 0, 0, 0); get_canvas()->flash(); gui->update_tool(); break; + } } //printf("CWindowCanvas::do_ruler 2 %f %f %f %f\n", gui->ruler_x1, gui->ruler_y1, gui->ruler_x2, gui->ruler_y2); } - else - { + else { // printf("CWindowCanvas::do_ruler 2 %f %f %f %f\n", // canvas_cursor_x, // canvas_cursor_y, // canvas_x1, // canvas_y1); - if(canvas_cursor_x >= canvas_x1 - RULERHANDLE_W / 2 && + if( canvas_cursor_x >= canvas_x1 - RULERHANDLE_W / 2 && canvas_cursor_x < canvas_x1 + RULERHANDLE_W / 2 && canvas_cursor_y >= canvas_y1 - RULERHANDLE_W && - canvas_cursor_y < canvas_y1 + RULERHANDLE_H / 2) - { + canvas_cursor_y < canvas_y1 + RULERHANDLE_H / 2 ) { set_cursor(UPRIGHT_ARROW_CURSOR); } else - if(canvas_cursor_x >= canvas_x2 - RULERHANDLE_W / 2 && + if( canvas_cursor_x >= canvas_x2 - RULERHANDLE_W / 2 && canvas_cursor_x < canvas_x2 + RULERHANDLE_W / 2 && canvas_cursor_y >= canvas_y2 - RULERHANDLE_W && - canvas_cursor_y < canvas_y2 + RULERHANDLE_H / 2) - { + canvas_cursor_y < canvas_y2 + RULERHANDLE_H / 2 ) { set_cursor(UPRIGHT_ARROW_CURSOR); } else @@ -1372,8 +1332,7 @@ int CWindowCanvas::do_ruler(int draw, int motion, } // Assume no ruler measurement if 0 length - if(draw && (!EQUIV(x2, x1) || !EQUIV(y2, y1))) - { + if( draw && (!EQUIV(x2, x1) || !EQUIV(y2, y1)) ) { get_canvas()->set_inverse(); get_canvas()->set_color(WHITE); get_canvas()->draw_line((int)canvas_x1, @@ -1424,7 +1383,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, Track *track = gui->cwindow->calculate_mask_track(); //printf("CWindowCanvas::do_mask 2\n"); - if(!track) return 0; + if( !track ) return 0; //printf("CWindowCanvas::do_mask 3\n"); CWindowMaskGUI *mask_gui = (CWindowMaskGUI *) (gui->tool_panel ? gui->tool_panel->tool_gui : 0); @@ -1501,7 +1460,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, mask_cursor_y = (mask_cursor_y - projector_y) / projector_z + half_track_h; // Fix cursor origin - if(button_press) { + if( button_press ) { gui->x_origin = mask_cursor_x; gui->y_origin = mask_cursor_y; } @@ -1522,8 +1481,8 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, ArrayList x_points; ArrayList y_points; - if(!cursor_motion) { - if(draw) { + if( !cursor_motion ) { + if( draw ) { get_canvas()->set_color(WHITE); get_canvas()->set_inverse(); } @@ -1531,19 +1490,19 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, // Never draw closed polygon and a closed // polygon is harder to add points to. - for(int i = 0; i < points.size() && !result; i++) { + for( int i = 0; i < points.size() && !result; i++ ) { MaskPoint *point1 = points.get(i); MaskPoint *point2 = (i >= points.size() - 1) ? points.get(0) : points.get(i + 1); - if(button_press) { + if( button_press ) { float point_distance1 = line_dist(point1->x,point1->y, mask_cursor_x,mask_cursor_y); - if(point_distance1 < shortest_point_distance || shortest_point < 0) { + if( point_distance1 < shortest_point_distance || shortest_point < 0 ) { shortest_point_distance = point_distance1; shortest_point = i; } float point_distance2 = line_dist(point2->x,point2->y, mask_cursor_x,mask_cursor_y); - if(point_distance2 < shortest_point_distance || shortest_point < 0) { + if( point_distance2 < shortest_point_distance || shortest_point < 0 ) { shortest_point_distance = point_distance2; shortest_point = (i >= points.size() - 1) ? 0 : (i + 1); } @@ -1553,7 +1512,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f projectorz=%f\n", //point1->x, point1->y, point2->x, point2->y, projector_z); - for(int j = 0; j <= segments && !result; j++) { + for( int j = 0; j <= segments && !result; j++ ) { //printf("CWindowCanvas::do_mask 1 %f, %f -> %f, %f\n", x0, y0, x3, y3); float x0 = point1->x, y0 = point1->y; float x1 = point1->x + point1->control_x2; @@ -1588,13 +1547,13 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, float canvas_x = (x - half_track_w) * projector_z + projector_x; float canvas_y = (y - half_track_h) * projector_z + projector_y; // Test new point addition - if(button_press) { + if( button_press ) { float line_distance = line_dist(x,y, mask_cursor_x,mask_cursor_y); //printf("CWindowCanvas::do_mask 1 x=%f cursor_x=%f y=%f cursor_y=%f %f %f %d, %d\n", // x, cursor_x, y, cursor_y, line_distance, shortest_line_distance, shortest_point1, shortest_point2); - if(line_distance < shortest_line_distance || - shortest_point1 < 0) { + if( line_distance < shortest_line_distance || + shortest_point1 < 0 ) { shortest_line_distance = line_distance; shortest_point1 = i; shortest_point2 = (i >= points.size() - 1) ? 0 : (i + 1); @@ -1604,19 +1563,19 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, // Test existing point selection // Test first point - if(gui->ctrl_down()) { + if( gui->ctrl_down() ) { float distance = line_dist(x1,y1, mask_cursor_x,mask_cursor_y); - if(distance < selected_control_point_distance) { + if( distance < selected_control_point_distance ) { selected_point = i; selected_control_point = 1; selected_control_point_distance = distance; } } else { - if(!gui->shift_down()) { + if( !gui->shift_down() ) { output_to_canvas(mwindow->edl, 0, canvas_x0, canvas_y0); - if(test_bbox(cursor_x, cursor_y, canvas_x0, canvas_y0)) { + if( test_bbox(cursor_x, cursor_y, canvas_x0, canvas_y0) ) { selected_point = i; } } @@ -1625,20 +1584,20 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } } // Test second point - if(gui->ctrl_down()) { + if( gui->ctrl_down() ) { float distance = line_dist(x2,y2, mask_cursor_x,mask_cursor_y); //printf("CWindowCanvas::do_mask %d %f %f\n", i, distance, selected_control_point_distance); - if(distance < selected_control_point_distance) { + if( distance < selected_control_point_distance ) { selected_point = (i < points.size() - 1 ? i + 1 : 0); selected_control_point = 0; selected_control_point_distance = distance; } } - else if(i < points.size() - 1) { - if(!gui->shift_down()) { + else if( i < points.size() - 1 ) { + if( !gui->shift_down() ) { output_to_canvas(mwindow->edl, 0, canvas_x3, canvas_y3); - if(test_bbox(cursor_x, cursor_y, canvas_x3, canvas_y3)) { + if( test_bbox(cursor_x, cursor_y, canvas_x3, canvas_y3) ) { selected_point = (i < points.size() - 1 ? i + 1 : 0); } } @@ -1659,8 +1618,8 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, if( j == segments ) { if( draw && draw_markers ) { // Draw second anchor - if(i < points.size() - 1) { - if(i == gui->affected_point - 1) + if( i < points.size() - 1 ) { + if( i == gui->affected_point - 1 ) get_canvas()->draw_disc( (int)canvas_x - CONTROL_W / 2, (int)canvas_y - CONTROL_W / 2, @@ -1784,7 +1743,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, //printf("CWindowCanvas::do_mask 1\n"); } - if(button_press && !result) { + if( button_press && !result ) { gui->affected_track = gui->cwindow->calculate_mask_track(); // Get keyframe outside the EDL to edit. This must be rendered @@ -1819,27 +1778,27 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } else // Translate entire keyframe - if(gui->alt_down() && mask->points.size()) { + if( gui->alt_down() && mask->points.size() ) { mwindow->undo->update_undo_before(_("mask translate"), 0); gui->current_operation = CWINDOW_MASK_TRANSLATE; gui->affected_point = 0; } else // Existing point or control point was selected - if(selected_point >= 0) { + if( selected_point >= 0 ) { mwindow->undo->update_undo_before(_("mask adjust"), 0); gui->affected_point = selected_point; - if(selected_control_point == 0) + if( selected_control_point == 0 ) gui->current_operation = CWINDOW_MASK_CONTROL_IN; else - if(selected_control_point == 1) + if( selected_control_point == 1 ) gui->current_operation = CWINDOW_MASK_CONTROL_OUT; else gui->current_operation = mwindow->edl->session->cwindow_operation; } else // No existing point or control point was selected so create a new one - if(!gui->ctrl_down() && !gui->alt_down()) { + if( !gui->ctrl_down() && !gui->alt_down() ) { mwindow->undo->update_undo_before(_("mask point"), 0); // Create the template MaskPoint *point = new MaskPoint; @@ -1851,7 +1810,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, point->control_y2 = 0; - if(shortest_point2 < shortest_point1) { + if( shortest_point2 < shortest_point1 ) { shortest_point2 ^= shortest_point1; shortest_point1 ^= shortest_point2; shortest_point2 ^= shortest_point1; @@ -1882,12 +1841,12 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, #else // Need to apply the new point to every keyframe - for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto; current; ) { + for( MaskAuto *current = (MaskAuto*)mask_autos->default_auto; current; ) { SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask); MaskPoint *new_point = new MaskPoint; submask->points.append(new_point); *new_point = *point; - if(current == (MaskAuto*)mask_autos->default_auto) + if( current == (MaskAuto*)mask_autos->default_auto ) current = (MaskAuto*)mask_autos->first; else current = (MaskAuto*)NEXT; @@ -1899,17 +1858,17 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } else // Insert between 2 points, shifting back point 2 - if(shortest_point1 >= 0 && shortest_point2 >= 0) { + if( shortest_point1 >= 0 && shortest_point2 >= 0 ) { #ifdef USE_KEYFRAME_SPANNING // In case the keyframe point count isn't synchronized with the rest of the keyframes, // avoid a crash. - if(points.size() >= shortest_point2) { + if( points.size() >= shortest_point2 ) { MaskPoint *new_point = new MaskPoint; points.append(0); - for(int i = points.size() - 1; + for( int i = points.size() - 1; i > shortest_point2; - i--) + i-- ) points.values[i] = points.values[i - 1]; points.values[shortest_point2] = new_point; @@ -1918,23 +1877,23 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, #else - for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto; current; ) { + for( MaskAuto *current = (MaskAuto*)mask_autos->default_auto; current; ) { SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask); // In case the keyframe point count isn't synchronized with the rest of the keyframes, // avoid a crash. - if(submask->points.size() >= shortest_point2) { + if( submask->points.size() >= shortest_point2 ) { MaskPoint *new_point = new MaskPoint; submask->points.append(0); - for(int i = submask->points.size() - 1; + for( int i = submask->points.size() - 1; i > shortest_point2; - i--) + i-- ) submask->points.values[i] = submask->points.values[i - 1]; submask->points.values[shortest_point2] = new_point; *new_point = *point; } - if(current == (MaskAuto*)mask_autos->default_auto) + if( current == (MaskAuto*)mask_autos->default_auto ) current = (MaskAuto*)mask_autos->first; else current = (MaskAuto*)NEXT; @@ -1950,7 +1909,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, // mwindow->edl->dump(); // printf("CWindowGUI::do_mask 30\n"); - if(!result) { + if( !result ) { //printf("CWindowCanvas::do_mask 1\n"); // Create the first point. #ifdef USE_KEYFRAME_SPANNING @@ -1959,12 +1918,12 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, *new_point = *point; gui->affected_point = points.size() - 1; #else - for(MaskAuto *current = (MaskAuto*)mask_autos->default_auto; current; ) { + for( MaskAuto *current = (MaskAuto*)mask_autos->default_auto; current; ) { SubMask *submask = current->get_submask(mwindow->edl->session->cwindow_mask); MaskPoint *new_point = new MaskPoint; submask->points.append(new_point); *new_point = *point; - if(current == (MaskAuto*)mask_autos->default_auto) + if( current == (MaskAuto*)mask_autos->default_auto ) current = (MaskAuto*)mask_autos->first; else current = (MaskAuto*)NEXT; @@ -1985,7 +1944,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, redraw = 1; } - if(button_press && result) { + if( button_press && result ) { #ifdef USE_KEYFRAME_SPANNING MaskPoints &mask_points = points; #else @@ -2044,7 +2003,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, float last_control_y2 = point->control_y2; int rotate = 0; - switch(gui->current_operation) { + switch( gui->current_operation ) { case CWINDOW_MASK: //printf("CWindowCanvas::do_mask %d %d\n", __LINE__, gui->affected_point); point->x = mask_cursor_x - gui->x_origin + gui->center_x; @@ -2166,10 +2125,10 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, } } else - if(gui->current_operation == CWINDOW_NONE) { + if( gui->current_operation == CWINDOW_NONE ) { // printf("CWindowCanvas::do_mask %d\n", __LINE__); int over_point = 0; - for(int i = 0; i < points.size() && !over_point; i++) { + for( int i = 0; i < points.size() && !over_point; i++ ) { MaskPoint *point = points.get(i); float x0 = point->x; float y0 = point->y; @@ -2181,22 +2140,22 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, float canvas_y0 = (y0 - half_track_h) * projector_z + projector_y; output_to_canvas(mwindow->edl, 0, canvas_x0, canvas_y0); - if(test_bbox(cursor_x, cursor_y, canvas_x0, canvas_y0)) { + if( test_bbox(cursor_x, cursor_y, canvas_x0, canvas_y0) ) { over_point = 1; } - if(!over_point && gui->ctrl_down()) { + if( !over_point && gui->ctrl_down() ) { float canvas_x1 = (x1 - half_track_w) * projector_z + projector_x; float canvas_y1 = (y1 - half_track_h) * projector_z + projector_y; output_to_canvas(mwindow->edl, 0, canvas_x1, canvas_y1); - if(test_bbox(cursor_x, cursor_y, canvas_x1, canvas_y1)) { + if( test_bbox(cursor_x, cursor_y, canvas_x1, canvas_y1) ) { over_point = 1; } else { float canvas_x2 = (x2 - half_track_w) * projector_z + projector_x; float canvas_y2 = (y2 - half_track_h) * projector_z + projector_y; output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2); - if(test_bbox(cursor_x, cursor_y, canvas_x2, canvas_y2)) { + if( test_bbox(cursor_x, cursor_y, canvas_x2, canvas_y2) ) { over_point = 1; } } @@ -2213,7 +2172,7 @@ int CWindowCanvas::do_mask(int &redraw, int &rerender, #ifdef USE_KEYFRAME_SPANNING // Must commit change after operation. - if(rerender && track) { + if( rerender && track ) { // Swap EDL keyframe with original. // Apply new values to keyframe span MaskAuto temp_keyframe(mwindow->edl, mask_autos); @@ -2289,11 +2248,9 @@ int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw) - if(refresh_frame && refresh_frame->get_w()>0 && refresh_frame->get_h()>0) - { + if( refresh_frame && refresh_frame->get_w()>0 && refresh_frame->get_h()>0 ) { - if(draw) - { + if( draw ) { row1 = gui->eyedrop_y - radius; row2 = gui->eyedrop_y + radius; column1 = gui->eyedrop_x - radius; @@ -2304,8 +2261,8 @@ int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw) CLAMP(column1, 0, refresh_frame->get_w() - 1); CLAMP(column2, 0, refresh_frame->get_w() - 1); - if(row2 <= row1) row2 = row1 + 1; - if(column2 <= column1) column2 = column1 + 1; + if( row2 <= row1 ) row2 = row1 + 1; + if( column2 <= column1 ) column2 = column1 + 1; float x1 = column1; float y1 = row1; @@ -2316,8 +2273,7 @@ int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw) output_to_canvas(mwindow->edl, 0, x2, y2); //printf("CWindowCanvas::do_eyedrop %d %f %f %f %f\n", __LINE__, x1, x2, y1, y2); - if(x2 - x1 >= 1 && y2 - y1 >= 1) - { + if( x2 - x1 >= 1 && y2 - y1 >= 1 ) { get_canvas()->set_inverse(); get_canvas()->set_color(WHITE); @@ -2333,20 +2289,17 @@ int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw) } } - if(button_press) - { + if( button_press ) { gui->current_operation = CWINDOW_EYEDROP; gui->tool_panel->raise_window(); } - if(gui->current_operation == CWINDOW_EYEDROP) - { + if( gui->current_operation == CWINDOW_EYEDROP ) { mwindow->undo->update_undo_before(_("Eyedrop"), this); // Get color out of frame. // Doesn't work during playback because that bypasses the refresh frame. - if(refresh_frame && refresh_frame->get_w()>0 && refresh_frame->get_h()>0) - { + if( refresh_frame && refresh_frame->get_w()>0 && refresh_frame->get_h()>0 ) { float cursor_x = get_cursor_x(); float cursor_y = get_cursor_y(); canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y); @@ -2361,13 +2314,12 @@ int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw) CLAMP(row2, 0, refresh_frame->get_h() - 1); CLAMP(column1, 0, refresh_frame->get_w() - 1); CLAMP(column2, 0, refresh_frame->get_w() - 1); - if(row2 <= row1) row2 = row1 + 1; - if(column2 <= column1) column2 = column1 + 1; + if( row2 <= row1 ) row2 = row1 + 1; + if( column2 <= column1 ) column2 = column1 + 1; // hide it - if(gui->eyedrop_visible) - { + if( gui->eyedrop_visible ) { int temp; do_eyedrop(temp, 0, 1); gui->eyedrop_visible = 0; @@ -2397,7 +2349,7 @@ int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw) float red = (float)*row++ / max; \ float green = (float)*row++ / max; \ float blue = (float)*row++ / max; \ - if(do_yuv) \ + if( do_yuv ) \ { \ float r = red + V_TO_R * (blue - 0.5); \ float g = red + U_TO_G * (green - 0.5) + V_TO_G * (blue - 0.5); \ @@ -2405,18 +2357,18 @@ int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw) mwindow->edl->local_session->red += r; \ mwindow->edl->local_session->green += g; \ mwindow->edl->local_session->blue += b; \ - if(r > mwindow->edl->local_session->red_max) mwindow->edl->local_session->red_max = r; \ - if(g > mwindow->edl->local_session->green_max) mwindow->edl->local_session->green_max = g; \ - if(b > mwindow->edl->local_session->blue_max) mwindow->edl->local_session->blue_max = b; \ + if( r > mwindow->edl->local_session->red_max ) mwindow->edl->local_session->red_max = r; \ + if( g > mwindow->edl->local_session->green_max ) mwindow->edl->local_session->green_max = g; \ + if( b > mwindow->edl->local_session->blue_max ) mwindow->edl->local_session->blue_max = b; \ } \ else \ { \ mwindow->edl->local_session->red += red; \ mwindow->edl->local_session->green += green; \ mwindow->edl->local_session->blue += blue; \ - if(red > mwindow->edl->local_session->red_max) mwindow->edl->local_session->red_max = red; \ - if(green > mwindow->edl->local_session->green_max) mwindow->edl->local_session->green_max = green; \ - if(blue > mwindow->edl->local_session->blue_max) mwindow->edl->local_session->blue_max = blue; \ + if( red > mwindow->edl->local_session->red_max ) mwindow->edl->local_session->red_max = red; \ + if( green > mwindow->edl->local_session->green_max ) mwindow->edl->local_session->green_max = green; \ + if( blue > mwindow->edl->local_session->blue_max ) mwindow->edl->local_session->blue_max = blue; \ } \ } @@ -2428,11 +2380,9 @@ int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw) mwindow->edl->local_session->red_max = 0; mwindow->edl->local_session->green_max = 0; mwindow->edl->local_session->blue_max = 0; - for(int i = row1; i < row2; i++) - { - for(int j = column1; j < column2; j++) - { - switch(refresh_frame->get_color_model()) + for( int i = row1; i < row2; i++ ) { + for( int j = column1; j < column2; j++ ) { + switch( refresh_frame->get_color_model() ) { case BC_YUV888: GET_COLOR(unsigned char, 3, 0xff, 1); @@ -2467,8 +2417,7 @@ int CWindowCanvas::do_eyedrop(int &rerender, int button_press, int draw) mwindow->edl->local_session->blue /= (row2 - row1) * (column2 - column1); } - else - { + else { mwindow->edl->local_session->red = 0; mwindow->edl->local_session->green = 0; mwindow->edl->local_session->blue = 0; @@ -2510,13 +2459,11 @@ int CWindowCanvas::need_overlays() void CWindowCanvas::draw_overlays() { - if(mwindow->edl->session->safe_regions) - { + if( mwindow->edl->session->safe_regions ) { draw_safe_regions(); } - if(mwindow->edl->session->cwindow_scrollbars) - { + if( mwindow->edl->session->cwindow_scrollbars ) { // Always draw output rectangle float x1, y1, x2, y2; x1 = 0; @@ -2528,17 +2475,12 @@ void CWindowCanvas::draw_overlays() get_canvas()->set_inverse(); get_canvas()->set_color(WHITE); - - get_canvas()->draw_rectangle((int)x1, - (int)y1, - (int)(x2 - x1), - (int)(y2 - y1)); - + int ix1 = x1-1, iy1 = y1-1, ix2 = x2+1, iy2 = y2+1; + get_canvas()->draw_rectangle(ix1, iy1, ix2-ix1, iy2-iy1); get_canvas()->set_opaque(); } - if(gui->highlighted) - { + if( gui->highlighted ) { get_canvas()->set_color(WHITE); get_canvas()->set_inverse(); get_canvas()->draw_rectangle(0, 0, get_canvas()->get_w(), get_canvas()->get_h()); @@ -2548,7 +2490,7 @@ void CWindowCanvas::draw_overlays() int temp1 = 0, temp2 = 0; //printf("CWindowCanvas::draw_overlays 1 %d\n", mwindow->edl->session->cwindow_operation); - switch(mwindow->edl->session->cwindow_operation) + switch( mwindow->edl->session->cwindow_operation ) { case CWINDOW_CAMERA: draw_outlines(1); @@ -2571,8 +2513,7 @@ void CWindowCanvas::draw_overlays() break; case CWINDOW_EYEDROP: - if(gui->eyedrop_visible) - { + if( gui->eyedrop_visible ) { int rerender; do_eyedrop(rerender, 0, 1); gui->eyedrop_visible = 1; @@ -2693,38 +2634,33 @@ int CWindowCanvas::test_crop(int button_press, int &redraw) output_to_canvas(mwindow->edl, 0, canvas_x2, canvas_y2); - if(gui->current_operation == CWINDOW_CROP) - { + if( gui->current_operation == CWINDOW_CROP ) { handle_selected = gui->crop_handle; } else - if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W && - canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H) - { + if( canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W && + canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H ) { handle_selected = 0; gui->crop_origin_x = x1; gui->crop_origin_y = y1; } else - if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 && - canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H) - { + if( canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 && + canvas_cursor_y >= canvas_y1 && canvas_cursor_y < canvas_y1 + CROPHANDLE_H ) { handle_selected = 1; gui->crop_origin_x = x2; gui->crop_origin_y = y1; } else - if(canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W && - canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2) - { + if( canvas_cursor_x >= canvas_x1 && canvas_cursor_x < canvas_x1 + CROPHANDLE_W && + canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2 ) { handle_selected = 2; gui->crop_origin_x = x1; gui->crop_origin_y = y2; } else - if(canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 && - canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2) - { + if( canvas_cursor_x >= canvas_x2 - CROPHANDLE_W && canvas_cursor_x < canvas_x2 && + canvas_cursor_y >= canvas_y2 - CROPHANDLE_H && canvas_cursor_y < canvas_y2 ) { handle_selected = 3; gui->crop_origin_x = x2; gui->crop_origin_y = y2; @@ -2741,10 +2677,8 @@ int CWindowCanvas::test_crop(int button_press, int &redraw) // handle_selected); // Start dragging. - if(button_press) - { - if(gui->alt_down()) - { + if( button_press ) { + if( gui->alt_down() ) { gui->crop_translate = 1; gui->crop_origin_x1 = x1; gui->crop_origin_y1 = y1; @@ -2761,8 +2695,7 @@ int CWindowCanvas::test_crop(int button_press, int &redraw) gui->tool_panel->raise_window(); result = 1; - if(handle_selected < 0 && !gui->crop_translate) - { + if( handle_selected < 0 && !gui->crop_translate ) { x2 = x1 = cursor_x; y2 = y1 = cursor_y; mwindow->edl->session->crop_x1 = (int)x1; @@ -2774,8 +2707,7 @@ int CWindowCanvas::test_crop(int button_press, int &redraw) } else // Translate all 4 points - if(gui->current_operation == CWINDOW_CROP && gui->crop_translate) - { + if( gui->current_operation == CWINDOW_CROP && gui->crop_translate ) { x1 = cursor_x - gui->x_origin + gui->crop_origin_x1; y1 = cursor_y - gui->y_origin + gui->crop_origin_y1; x2 = cursor_x - gui->x_origin + gui->crop_origin_x2; @@ -2790,40 +2722,32 @@ int CWindowCanvas::test_crop(int button_press, int &redraw) } else // Update dragging - if(gui->current_operation == CWINDOW_CROP) - { - switch(gui->crop_handle) - { - case -1: - x1 = gui->crop_origin_x; - y1 = gui->crop_origin_y; - x2 = gui->crop_origin_x; - y2 = gui->crop_origin_y; - if(cursor_x < gui->x_origin) - { - if(cursor_y < gui->y_origin) - { + if( gui->current_operation == CWINDOW_CROP ) { + switch( gui->crop_handle ) { + case -1: + x1 = gui->crop_origin_x; + y1 = gui->crop_origin_y; + x2 = gui->crop_origin_x; + y2 = gui->crop_origin_y; + if( cursor_x < gui->x_origin ) { + if( cursor_y < gui->y_origin ) { x1 = cursor_x; y1 = cursor_y; } else - if(cursor_y >= gui->y_origin) - { + if( cursor_y >= gui->y_origin ) { x1 = cursor_x; y2 = cursor_y; } } else - if(cursor_x >= gui->x_origin) - { - if(cursor_y < gui->y_origin) - { + if( cursor_x >= gui->x_origin ) { + if( cursor_y < gui->y_origin ) { y1 = cursor_y; x2 = cursor_x; } else - if(cursor_y >= gui->y_origin) - { + if( cursor_y >= gui->y_origin ) { x2 = cursor_x; y2 = cursor_y; } @@ -2853,38 +2777,33 @@ int CWindowCanvas::test_crop(int button_press, int &redraw) break; } - if(!EQUIV(mwindow->edl->session->crop_x1, x1) || + if( !EQUIV(mwindow->edl->session->crop_x1, x1) || !EQUIV(mwindow->edl->session->crop_x2, x2) || !EQUIV(mwindow->edl->session->crop_y1, y1) || - !EQUIV(mwindow->edl->session->crop_y2, y2)) - { - if (x1 > x2) - { + !EQUIV(mwindow->edl->session->crop_y2, y2) ) { + if( x1 > x2 ) { float tmp = x1; x1 = x2; x2 = tmp; - switch (gui->crop_handle) - { - case 0: gui->crop_handle = 1; break; - case 1: gui->crop_handle = 0; break; - case 2: gui->crop_handle = 3; break; - case 3: gui->crop_handle = 2; break; - default: break; + switch( gui->crop_handle ) { + case 0: gui->crop_handle = 1; break; + case 1: gui->crop_handle = 0; break; + case 2: gui->crop_handle = 3; break; + case 3: gui->crop_handle = 2; break; + default: break; } } - if (y1 > y2) - { + if( y1 > y2 ) { float tmp = y1; y1 = y2; y2 = tmp; - switch (gui->crop_handle) - { - case 0: gui->crop_handle = 2; break; - case 1: gui->crop_handle = 3; break; - case 2: gui->crop_handle = 0; break; - case 3: gui->crop_handle = 1; break; - default: break; + switch( gui->crop_handle ) { + case 0: gui->crop_handle = 2; break; + case 1: gui->crop_handle = 3; break; + case 2: gui->crop_handle = 0; break; + case 3: gui->crop_handle = 1; break; + default: break; } } @@ -2898,33 +2817,21 @@ int CWindowCanvas::test_crop(int button_press, int &redraw) } else // Update cursor font - if(handle_selected >= 0) - { - switch(handle_selected) - { - case 0: - set_cursor(UPLEFT_RESIZE); - break; - case 1: - set_cursor(UPRIGHT_RESIZE); - break; - case 2: - set_cursor(DOWNLEFT_RESIZE); - break; - case 3: - set_cursor(DOWNRIGHT_RESIZE); - break; + if( handle_selected >= 0 ) { + switch( handle_selected ) { + case 0: set_cursor(UPLEFT_RESIZE); break; + case 1: set_cursor(UPRIGHT_RESIZE); break; + case 2: set_cursor(DOWNLEFT_RESIZE); break; + case 3: set_cursor(DOWNRIGHT_RESIZE); break; } result = 1; } - else - { + else { set_cursor(ARROW_CURSOR); } #define CLAMP(x, y, z) ((x) = ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x)))) - if(redraw) - { + if( redraw ) { CLAMP(mwindow->edl->session->crop_x1, 0, mwindow->edl->session->output_w); CLAMP(mwindow->edl->session->crop_x2, 0, mwindow->edl->session->output_w); CLAMP(mwindow->edl->session->crop_y1, 0, mwindow->edl->session->output_h); @@ -2952,7 +2859,7 @@ void CWindowCanvas::draw_crop() output_to_canvas(mwindow->edl, 0, x1, y1); output_to_canvas(mwindow->edl, 0, x2, y2); - if(x2 - x1 && y2 - y1) + if( x2 - x1 && y2 - y1 ) get_canvas()->draw_rectangle((int)x1, (int)y1, (int)(x2 - x1), @@ -2970,7 +2877,7 @@ void CWindowCanvas::draw_outlines(int do_camera) { Track *track = gui->cwindow->calculate_affected_track(); - if(!track) return; + if( !track ) return; float proj_x, proj_y, proj_z; int64_t position = track->to_units( @@ -3163,65 +3070,56 @@ int CWindowCanvas::test_bezier(int button_press, return result; } - int CWindowCanvas::test_zoom(int &redraw) { - int result = 0; - float x, y; float zoom = 0; - - if( mwindow->edl->session->cwindow_scrollbars ) { - if( *gui->zoom_panel->get_text() != 'x' ) { -// Find current zoom in table - int idx = total_zooms; float old_zoom = get_zoom(); - while( --idx >= 0 && !EQUIV(my_zoom_table[idx], old_zoom) ); - if( idx >= 0 ) { - idx += get_buttonpress() == 5 || - gui->ctrl_down() || gui->shift_down() ? -1 : +1 ; - CLAMP(idx, 0, total_zooms-1); - zoom = my_zoom_table[idx]; - } + int button = get_buttonpress(); + if( button == LEFT_BUTTON ) + button = gui->shift_down() ? WHEEL_DOWN : WHEEL_UP; + if( !(zoom = get_zoom()) ) + zoom = get_auto_zoom(mwindow->edl); + switch( button ) { + case WHEEL_UP: { + int idx = 0; + for( ; idx < total_zooms; ++idx ) { + if( EQUIV(zoom, my_zoom_table[idx]) ) continue; + if( zoom < my_zoom_table[idx] ) break; } - x = get_cursor_x(); y = get_cursor_y(); - if( !zoom ) { - mwindow->edl->session->cwindow_scrollbars = 0; - gui->zoom_panel->update(0); - zoom = gui->get_auto_zoom(); + zoom = idx < total_zooms ? my_zoom_table[idx] : 1.1 * zoom; + break; } + case WHEEL_DOWN: { + int idx = total_zooms; + for( ; --idx >= 0; ) { + if( EQUIV(my_zoom_table[idx], zoom) ) continue; + if( my_zoom_table[idx] < zoom ) break; } - else { - gui->zoom_panel->ZoomPanel::update(zoom); - float output_x = x, output_y = y; - canvas_to_output(mwindow->edl, 0, output_x, output_y); - x = output_x - x / zoom; - y = output_y - y / zoom; + zoom = idx >= 0 ? my_zoom_table[idx] : 0.9 * zoom; + break; } + case MIDDLE_BUTTON: + if( gui->shift_down() ) { + zoom = 0; + break; } + default: // fall thru + return 0; } - else { - mwindow->edl->session->cwindow_scrollbars = 1; - x = (mwindow->edl->session->output_w - w) / 2; - y = (mwindow->edl->session->output_h - h) / 2; - zoom = 1; - } - update_zoom((int)x, (int)y, zoom); - - gui->composite_panel->cpanel_zoom->update(zoom); - - reposition_window(mwindow->edl, - mwindow->theme->ccanvas_x, mwindow->theme->ccanvas_y, - mwindow->theme->ccanvas_w, mwindow->theme->ccanvas_h); - redraw = 1; result = 1; - - return result; + float cx = get_cursor_x(), cy = get_cursor_y(); + set_zoom(mwindow->edl, zoom, cx, cy); + gui->zoom_panel->update(zoom); + gui->update_canvas(); + redraw = 1; + return 1; } void CWindowCanvas::calculate_origin() { - gui->x_origin = get_cursor_x(); - gui->y_origin = get_cursor_y(); -//printf("CWindowCanvas::calculate_origin 1 %f %f\n", gui->x_origin, gui->y_origin); - canvas_to_output(mwindow->edl, 0, gui->x_origin, gui->y_origin); -//printf("CWindowCanvas::calculate_origin 2 %f %f\n", gui->x_origin, gui->y_origin); + float zoom_x, zoom_y, conformed_w, conformed_h; + get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h); + gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h); + gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h); + gui->x_origin = (float)get_cursor_x() / zoom_x + gui->x_offset; + gui->y_origin = (float)get_cursor_y() / zoom_y + gui->y_offset; } @@ -3234,28 +3132,27 @@ int CWindowCanvas::cursor_leave_event() int CWindowCanvas::cursor_enter_event() { int redraw = 0; - switch(mwindow->edl->session->cwindow_operation) - { - case CWINDOW_CAMERA: - case CWINDOW_PROJECTOR: - set_cursor(MOVE_CURSOR); - break; - case CWINDOW_ZOOM: - set_cursor(MOVE_CURSOR); - break; - case CWINDOW_CROP: - test_crop(0, redraw); - break; - case CWINDOW_PROTECT: - set_cursor(ARROW_CURSOR); - break; - case CWINDOW_MASK: - case CWINDOW_RULER: - set_cursor(CROSS_CURSOR); - break; - case CWINDOW_EYEDROP: - set_cursor(CROSS_CURSOR); - break; + switch( mwindow->edl->session->cwindow_operation ) { + case CWINDOW_CAMERA: + case CWINDOW_PROJECTOR: + set_cursor(MOVE_CURSOR); + break; + case CWINDOW_ZOOM: + set_cursor(MOVE_CURSOR); + break; + case CWINDOW_CROP: + test_crop(0, redraw); + break; + case CWINDOW_PROTECT: + set_cursor(ARROW_CURSOR); + break; + case CWINDOW_MASK: + case CWINDOW_RULER: + set_cursor(CROSS_CURSOR); + break; + case CWINDOW_EYEDROP: + set_cursor(CROSS_CURSOR); + break; } return 1; } @@ -3266,88 +3163,59 @@ int CWindowCanvas::cursor_motion_event() //printf("CWindowCanvas::cursor_motion_event %d current_operation=%d\n", __LINE__, gui->current_operation); - switch(gui->current_operation) - { - case CWINDOW_SCROLL: - { - float zoom = get_zoom(); - float cursor_x = get_cursor_x(); - float cursor_y = get_cursor_y(); - - float zoom_x, zoom_y, conformed_w, conformed_h; - get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h); - cursor_x = (float)cursor_x / zoom_x + gui->x_offset; - cursor_y = (float)cursor_y / zoom_y + gui->y_offset; + switch( gui->current_operation ) { + case CWINDOW_SCROLL: { + result = do_scroll(mwindow->edl, get_cursor_x(), get_cursor_y()); + break; } + case CWINDOW_RULER: + result = do_ruler(0, 1, 0, 0); + break; + case CWINDOW_CAMERA: + result = test_bezier(0, redraw, redraw_canvas, rerender, 1); + break; - int x = (int)(gui->x_origin - cursor_x + gui->x_offset); - int y = (int)(gui->y_origin - cursor_y + gui->y_offset); + case CWINDOW_PROJECTOR: + result = test_bezier(0, redraw, redraw_canvas, rerender, 0); + break; - update_zoom(x, - y, - zoom); - update_scrollbars(0); - redraw = 1; - result = 1; - break; - } + case CWINDOW_CROP: + result = test_crop(0, redraw); +// printf("CWindowCanvas::cursor_motion_event %d result=%d redraw=%d\n", +// __LINE__, result, redraw); + break; - case CWINDOW_RULER: - result = do_ruler(0, 1, 0, 0); - break; + case CWINDOW_MASK: + case CWINDOW_MASK_CONTROL_IN: + case CWINDOW_MASK_CONTROL_OUT: + case CWINDOW_MASK_TRANSLATE: + result = do_mask(redraw, rerender, 0, 1, 0); + break; - case CWINDOW_CAMERA: - result = test_bezier(0, redraw, redraw_canvas, rerender, 1); - break; + case CWINDOW_EYEDROP: + result = do_eyedrop(rerender, 0, 0); + break; - case CWINDOW_PROJECTOR: - result = test_bezier(0, redraw, redraw_canvas, rerender, 0); - break; + default: + break; + } +// cursor font changes + if( !result ) { +// printf("CWindowCanvas::cursor_motion_event %d cwindow_operation=%d\n", +// __LINE__, mwindow->edl->session->cwindow_operation); + switch( mwindow->edl->session->cwindow_operation ) { case CWINDOW_CROP: result = test_crop(0, redraw); -// printf("CWindowCanvas::cursor_motion_event %d result=%d redraw=%d\n", -// __LINE__, -// result, -// redraw); break; - + case CWINDOW_RULER: + result = do_ruler(0, 1, 0, 0); + break; case CWINDOW_MASK: - case CWINDOW_MASK_CONTROL_IN: - case CWINDOW_MASK_CONTROL_OUT: - case CWINDOW_MASK_TRANSLATE: result = do_mask(redraw, rerender, 0, 1, 0); break; - - case CWINDOW_EYEDROP: - result = do_eyedrop(rerender, 0, 0); - break; - - default: - break; - - } - - -// cursor font changes - if(!result) - { -// printf("CWindowCanvas::cursor_motion_event %d cwindow_operation=%d\n", -// __LINE__, -// mwindow->edl->session->cwindow_operation); - switch(mwindow->edl->session->cwindow_operation) - { - case CWINDOW_CROP: - result = test_crop(0, redraw); - break; - case CWINDOW_RULER: - result = do_ruler(0, 1, 0, 0); - break; - case CWINDOW_MASK: - result = do_mask(redraw, rerender, 0, 1, 0); - break; } } @@ -3364,70 +3232,60 @@ int CWindowCanvas::button_press_event() int redraw_canvas = 0; int rerender = 0; - if(Canvas::button_press_event()) return 1; + if( Canvas::button_press_event() ) return 1; gui->translating_zoom = gui->shift_down(); - calculate_origin(); -//printf("CWindowCanvas::button_press_event 2 %f %f\n", gui->x_origin, gui->y_origin, gui->x_origin, gui->y_origin); - - float zoom_x, zoom_y, conformed_w, conformed_h; - get_zooms(mwindow->edl, 0, zoom_x, zoom_y, conformed_w, conformed_h); - gui->x_offset = get_x_offset(mwindow->edl, 0, zoom_x, conformed_w, conformed_h); - gui->y_offset = get_y_offset(mwindow->edl, 0, zoom_y, conformed_w, conformed_h); // Scroll view if( mwindow->edl->session->cwindow_operation != CWINDOW_PROTECT && - get_buttonpress() == MIDDLE_BUTTON && !get_canvas()->shift_down() ) - { + get_buttonpress() == MIDDLE_BUTTON && !get_canvas()->shift_down() ) { gui->current_operation = CWINDOW_SCROLL; result = 1; } - else + else { // Adjust parameter - { - switch(mwindow->edl->session->cwindow_operation) - { - case CWINDOW_RULER: - result = do_ruler(0, 0, 1, 0); - break; + switch( mwindow->edl->session->cwindow_operation ) { + case CWINDOW_RULER: + result = do_ruler(0, 0, 1, 0); + break; - case CWINDOW_CAMERA: - result = test_bezier(1, redraw, redraw_canvas, rerender, 1); - break; + case CWINDOW_CAMERA: + result = test_bezier(1, redraw, redraw_canvas, rerender, 1); + break; - case CWINDOW_PROJECTOR: - result = test_bezier(1, redraw, redraw_canvas, rerender, 0); - break; + case CWINDOW_PROJECTOR: + result = test_bezier(1, redraw, redraw_canvas, rerender, 0); + break; - case CWINDOW_ZOOM: - result = test_zoom(redraw); - break; + case CWINDOW_ZOOM: + test_zoom(redraw); + break; - case CWINDOW_CROP: - result = test_crop(1, redraw); - break; + case CWINDOW_CROP: + result = test_crop(1, redraw); + break; - case CWINDOW_MASK: - switch( get_buttonpress() ) { - case LEFT_BUTTON: - result = do_mask(redraw, rerender, 1, 0, 0); - break; - case MIDDLE_BUTTON: { // && shift_down() - result = do_mask_focus(); - redraw = redraw_canvas = 1; - break; } - case WHEEL_UP: - case WHEEL_DOWN: - result = do_mask(redraw, rerender, 1, 1, 0); - break; - } - if( result ) redraw_canvas = 1; + case CWINDOW_MASK: + switch( get_buttonpress() ) { + case LEFT_BUTTON: + result = do_mask(redraw, rerender, 1, 0, 0); break; - - case CWINDOW_EYEDROP: - result = do_eyedrop(rerender, 1, 0); + case MIDDLE_BUTTON: { // && shift_down() + result = do_mask_focus(); + redraw = redraw_canvas = 1; + break; } + case WHEEL_UP: + case WHEEL_DOWN: + result = do_mask(redraw, rerender, 1, 1, 0); break; + } + if( result ) redraw_canvas = 1; + break; + + case CWINDOW_EYEDROP: + result = do_eyedrop(rerender, 1, 0); + break; } } @@ -3442,43 +3300,42 @@ int CWindowCanvas::button_release_event() int result = 0; const char *undo_label = 0; - switch(gui->current_operation) - { - case CWINDOW_SCROLL: - result = 1; - break; + switch( gui->current_operation ) { + case CWINDOW_SCROLL: + result = 1; + break; - case CWINDOW_RULER: - do_ruler(0, 0, 0, 1); - break; + case CWINDOW_RULER: + do_ruler(0, 0, 0, 1); + break; - case CWINDOW_CAMERA: - undo_label = _("camera"); - break; + case CWINDOW_CAMERA: + undo_label = _("camera"); + break; - case CWINDOW_PROJECTOR: - undo_label = _("projector"); - break; + case CWINDOW_PROJECTOR: + undo_label = _("projector"); + break; - case CWINDOW_MASK: - case CWINDOW_MASK_CONTROL_IN: - case CWINDOW_MASK_CONTROL_OUT: - case CWINDOW_MASK_TRANSLATE: + case CWINDOW_MASK: + case CWINDOW_MASK_CONTROL_IN: + case CWINDOW_MASK_CONTROL_OUT: + case CWINDOW_MASK_TRANSLATE: // Finish mask operation - gui->mask_keyframe = 0; - undo_label = _("mask"); - break; - case CWINDOW_MASK_ROTATE: - gui->mask_keyframe = 0; - undo_label = _("mask rotate"); - break; - case CWINDOW_MASK_SCALE: - gui->mask_keyframe = 0; - undo_label = _("mask scale"); - break; - case CWINDOW_NONE: - result = Canvas::button_release_event(); - break; + gui->mask_keyframe = 0; + undo_label = _("mask"); + break; + case CWINDOW_MASK_ROTATE: + gui->mask_keyframe = 0; + undo_label = _("mask rotate"); + break; + case CWINDOW_MASK_SCALE: + gui->mask_keyframe = 0; + undo_label = _("mask scale"); + break; + case CWINDOW_NONE: + result = Canvas::button_release_event(); + break; } if( undo_label ) @@ -3492,14 +3349,11 @@ void CWindowCanvas::zoom_resize_window(float percentage) int canvas_w, canvas_h; int new_w, new_h; - // Get required canvas size calculate_sizes(mwindow->edl->get_aspect_ratio(), mwindow->edl->session->output_w, mwindow->edl->session->output_h, - percentage, - canvas_w, - canvas_h); + percentage, canvas_w, canvas_h); // Estimate window size from current borders new_w = canvas_w + (gui->get_w() - mwindow->theme->ccanvas_w); diff --git a/cinelerra-5.1/cinelerra/cwindowgui.h b/cinelerra-5.1/cinelerra/cwindowgui.h index ddbfa372..2930efa0 100644 --- a/cinelerra-5.1/cinelerra/cwindowgui.h +++ b/cinelerra-5.1/cinelerra/cwindowgui.h @@ -68,8 +68,7 @@ public: void create_objects(); int resize_event(int w, int h); - void zoom_canvas(double value, int update_menu); - float get_auto_zoom(); + void update_canvas(int redraw=1); // Events for the fullscreen canvas fall through to here. int button_press_event(); @@ -286,6 +285,8 @@ public: int get_xscroll(); int get_yscroll(); float get_zoom(); + void zoom_auto(); + int do_scroll(EDL *edl, float cursor_x, float cursor_y); int do_eyedrop(int &rerender, int button_press, int draw); int do_mask(int &redraw, int &rerender, @@ -318,7 +319,9 @@ public: void reset_camera(); void reset_projector(); void draw_crophandle(int x, int y); - void zoom_auto(); + int use_fullscreen(int on); + void start_fullscreen(); + void stop_fullscreen(); // Draw the camera/projector overlay in different colors. void draw_outlines(int do_camera); diff --git a/cinelerra-5.1/cinelerra/lv2ui.C b/cinelerra-5.1/cinelerra/lv2ui.C index a025ef1c..7d0e3237 100644 --- a/cinelerra-5.1/cinelerra/lv2ui.C +++ b/cinelerra-5.1/cinelerra/lv2ui.C @@ -14,6 +14,7 @@ int main(int ac, char **av) const char *cp = getenv("BUG"); static int zbug = !cp ? 0 : atoi(cp); volatile int bug = zbug; while( bug ) usleep(10000); + BC_WindowBase::init_resources(1); BC_Signals signals; if( getenv("BC_TRAP_LV2_SEGV") ) { signals.initialize("/tmp/lv2ui_%d.dmp"); diff --git a/cinelerra-5.1/cinelerra/mwindow.C b/cinelerra-5.1/cinelerra/mwindow.C index ee89074e..c6c8235a 100644 --- a/cinelerra-5.1/cinelerra/mwindow.C +++ b/cinelerra-5.1/cinelerra/mwindow.C @@ -3660,6 +3660,7 @@ void MWindow::update_project(int load_mode) zwindow->set_title(mixer->title); zwindow->start(); } + cwindow->gui->canvas->set_zoom(edl, 0); } update_vwindow(); @@ -3669,6 +3670,7 @@ void MWindow::update_project(int load_mode) Track *track = cwindow->calculate_affected_track(); cwindow->mask_track_id = track ? track->get_id() : -1; cwindow->gui->tool_panel->raise_tool(); + cwindow->gui->update_canvas(0); cwindow->gui->unlock_window(); if(debug) PRINT_TRACE diff --git a/cinelerra-5.1/cinelerra/mwindowedit.C b/cinelerra-5.1/cinelerra/mwindowedit.C index 2d09eeb0..2db6fa0b 100644 --- a/cinelerra-5.1/cinelerra/mwindowedit.C +++ b/cinelerra-5.1/cinelerra/mwindowedit.C @@ -91,13 +91,6 @@ void MWindow::add_audio_track_entry(int above, Track *dst) restart_brender(); gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0); gui->activate_timeline(); - -// gui->get_scrollbars(0); -// gui->canvas->draw(); -// gui->patchbay->update(); -// gui->cursor->draw(1); -// gui->canvas->flash(); -// gui->canvas->activate(); cwindow->refresh_frame(CHANGE_EDL); } @@ -111,12 +104,6 @@ void MWindow::add_video_track_entry(Track *dst) gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0); gui->activate_timeline(); -// gui->get_scrollbars(0); -// gui->canvas->draw(); -// gui->patchbay->update(); -// gui->cursor->draw(1); -// gui->canvas->flash(); -// gui->canvas->activate(); cwindow->refresh_frame(CHANGE_EDL); save_backup(); } @@ -131,12 +118,6 @@ void MWindow::add_subttl_track_entry(Track *dst) gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0); gui->activate_timeline(); -// gui->get_scrollbars(0); -// gui->canvas->draw(); -// gui->patchbay->update(); -// gui->cursor->draw(1); -// gui->canvas->flash(); -// gui->canvas->activate(); cwindow->refresh_frame(CHANGE_EDL); save_backup(); } diff --git a/cinelerra-5.1/cinelerra/mwindowgui.C b/cinelerra-5.1/cinelerra/mwindowgui.C index 477d256c..2350f92e 100644 --- a/cinelerra-5.1/cinelerra/mwindowgui.C +++ b/cinelerra-5.1/cinelerra/mwindowgui.C @@ -150,102 +150,6 @@ MWindowGUI::~MWindowGUI() delete y_divider; } -#if 0 -void MWindowGUI::get_scrollbars(int flush) -{ - //int64_t h_needed = mwindow->edl->get_tracks_height(mwindow->theme); - //int64_t w_needed = mwindow->edl->get_tracks_width(); - int need_xscroll = 0; - int need_yscroll = 0; - view_w = mwindow->theme->mcanvas_w; - view_h = mwindow->theme->mcanvas_h; - -// Scrollbars are constitutive - need_xscroll = need_yscroll = 1; - view_h = mwindow->theme->mcanvas_h; - view_w = mwindow->theme->mcanvas_w; - -// for(int i = 0; i < 2; i++) -// { -// if(w_needed > view_w) -// { -// need_xscroll = 1; -// view_h = mwindow->theme->mcanvas_h - SCROLL_SPAN; -// } -// else -// need_xscroll = 0; -// -// if(h_needed > view_h) -// { -// need_yscroll = 1; -// view_w = mwindow->theme->mcanvas_w - SCROLL_SPAN; -// } -// else -// need_yscroll = 0; -// } -//printf("MWindowGUI::get_scrollbars 1\n"); - - if(canvas && (view_w != canvas->get_w() || view_h != canvas->get_h())) - { - canvas->reposition_window(mwindow->theme->mcanvas_x, - mwindow->theme->mcanvas_y, - view_w, - view_h); - } - - if(need_xscroll) - { - if(!samplescroll) - add_subwindow(samplescroll = new SampleScroll(mwindow, - this, - mwindow->theme->mhscroll_x, - mwindow->theme->mhscroll_y, - mwindow->theme->mhscroll_w)); - else - samplescroll->resize_event(); - - samplescroll->set_position(0); - } - else - { - if(samplescroll) delete samplescroll; - samplescroll = 0; - mwindow->edl->local_session->view_start = 0; - } - - - if(need_yscroll) - { -//printf("MWindowGUI::get_scrollbars 1.1 %p %p\n", this, canvas); - if(!trackscroll) - add_subwindow(trackscroll = new TrackScroll(mwindow, - this, - mwindow->theme->mvscroll_x, - mwindow->theme->mvscroll_y, - mwindow->theme->mvscroll_h)); - else - trackscroll->resize_event(); - - -//printf("MWindowGUI::get_scrollbars 1.2\n"); - trackscroll->update_length(mwindow->edl->get_tracks_height(mwindow->theme), - mwindow->edl->local_session->track_start, - view_h, - 0); -//printf("MWindowGUI::get_scrollbars 1.3\n"); - } - else - { - if(trackscroll) delete trackscroll; - trackscroll = 0; - mwindow->edl->local_session->track_start = 0; - } - - if(flush) this->flush(); - -} -#endif // 0 - void MWindowGUI::create_objects() { lock_window("MWindowGUI::create_objects"); @@ -288,26 +192,6 @@ void MWindowGUI::create_objects() mwindow->theme->mcanvas_h); pane[TOP_LEFT_PANE]->create_objects(); -// add_subwindow(timebar = new MTimeBar(mwindow, -// this, -// mwindow->theme->mtimebar_x, -// mwindow->theme->mtimebar_y, -// mwindow->theme->mtimebar_w, -// mwindow->theme->mtimebar_h)); -// timebar->create_objects(); - -// if(debug) printf("MWindowGUI::create_objects %d\n", __LINE__); -// add_subwindow(patchbay = new PatchBay(mwindow, this)); -// patchbay->create_objects(); - -// if(debug) printf("MWindowGUI::create_objects %d\n", __LINE__); -// get_scrollbars(0); - -// if(debug) printf("MWindowGUI::create_objects %d\n", __LINE__); -// mwindow->gui->add_subwindow(canvas = new TrackCanvas(mwindow, this)); -// canvas->create_objects(); - - if(debug) printf("MWindowGUI::create_objects %d\n", __LINE__); add_subwindow(zoombar = new ZoomBar(mwindow, this)); zoombar->create_objects(); diff --git a/cinelerra-5.1/cinelerra/pluginclient.C b/cinelerra-5.1/cinelerra/pluginclient.C index 5d7018c1..da9a6977 100644 --- a/cinelerra-5.1/cinelerra/pluginclient.C +++ b/cinelerra-5.1/cinelerra/pluginclient.C @@ -182,6 +182,244 @@ int PluginClientWindow::close_event() return 1; } +void PluginClientWindow::param_updated() +{ + printf("PluginClientWindow::param_updated %d undefined\n", __LINE__); +} + +//phyllis +PluginParam::PluginParam(PluginClient *plugin, PluginClientWindow *gui, + int x1, int x2, int x3, int y, int text_w, + int *output_i, float *output_f, int *output_q, + const char *title, float min, float max) +{ + this->output_i = output_i; + this->output_f = output_f; + this->output_q = output_q; + this->title = cstrdup(title); + this->plugin = plugin; + this->gui = gui; + this->x1 = x1; + this->x2 = x2; + this->x3 = x3; + this->text_w = text_w; + this->y = y; + this->min = min; + this->max = max; + fpot = 0; + ipot = 0; + qpot = 0; + text = 0; + precision = 2; +} +PluginParam::~PluginParam() +{ + delete fpot; + delete ipot; + delete qpot; + delete text; + delete title; +} + + +void PluginParam::initialize() +{ + BC_Title *title_; + int y2 = y + + (BC_Pot::calculate_h() - + BC_Title::calculate_h(gui, _(title), MEDIUMFONT)) / 2; + gui->add_tool(title_ = new BC_Title(x1, y2, _(title))); + + if(output_f) + { + gui->add_tool(fpot = new PluginFPot(this, x2, y)); + } + + if(output_i) + { + gui->add_tool(ipot = new PluginIPot(this, x2, y)); + } + + if(output_q) + { + gui->add_tool(qpot = new PluginQPot(this, x2, y)); + } + + int y3 = y + + (BC_Pot::calculate_h() - + BC_TextBox::calculate_h(gui, MEDIUMFONT, 1, 1)) / 2; + if(output_i) + { + gui->add_tool(text = new PluginText(this, x3, y3, *output_i)); + } + if(output_f) + { + gui->add_tool(text = new PluginText(this, x3, y3, *output_f)); + } + if(output_q) + { + gui->add_tool(text = new PluginText(this, x3, y3, *output_q)); + } + + set_precision(precision); +} + +void PluginParam::update(int skip_text, int skip_pot) +{ + if(!skip_text) + { + if(output_i) + { + text->update((int64_t)*output_i); + } + if(output_q) + { + text->update((int64_t)*output_q); + } + if(output_f) + { + text->update((float)*output_f); + } + } + + if(!skip_pot) + { + if(ipot) + { + ipot->update((int64_t)*output_i); + } + if(qpot) + { + qpot->update((int64_t)*output_q); + } + if(fpot) + { + fpot->update((float)*output_f); + } + } +} + +void PluginParam::set_precision(int digits) +{ + this->precision = digits; + if(fpot) + { + if(text) + { + text->set_precision(digits); + } + + fpot->set_precision(1.0f / pow(10, digits)); + } +} + + +PluginFPot::PluginFPot(PluginParam *param, int x, int y) + : BC_FPot(x, + y, + *param->output_f, + param->min, + param->max) +{ + this->param = param; + set_use_caption(0); +} + +int PluginFPot::handle_event() +{ + *param->output_f = get_value(); + param->update(0, 1); + param->plugin->send_configure_change(); + param->gui->param_updated(); + return 1; +} + +PluginIPot::PluginIPot(PluginParam *param, int x, int y) + : BC_IPot(x, + y, + *param->output_i, + (int)param->min, + (int)param->max) +{ + this->param = param; + set_use_caption(0); +} + +int PluginIPot::handle_event() +{ + *param->output_i = get_value(); + param->update(0, 1); + param->plugin->send_configure_change(); + param->gui->param_updated(); + return 1; +} + + +PluginQPot::PluginQPot(PluginParam *param, int x, int y) + : BC_QPot(x, + y, + *param->output_q) +{ + this->param = param; + set_use_caption(0); +} + +int PluginQPot::handle_event() +{ + *param->output_q = get_value(); + param->update(0, 1); + param->plugin->send_configure_change(); + param->gui->param_updated(); + return 1; +} + +PluginText::PluginText(PluginParam *param, int x, int y, int value) + : BC_TextBox(x, + y, + param->text_w, + 1, + (int64_t)value, + 1, + MEDIUMFONT) +{ + this->param = param; +} + +PluginText::PluginText(PluginParam *param, int x, int y, float value) + : BC_TextBox(x, + y, + param->text_w, + 1, + (float)value, + 1, + MEDIUMFONT, + param->precision) +{ + this->param = param; +} + +int PluginText::handle_event() +{ + if(param->output_i) + { + *param->output_i = atoi(get_text()); + } + + if(param->output_f) + { + *param->output_f = atof(get_text()); + } + + if(param->output_q) + { + *param->output_q = atoi(get_text()); + } + param->update(1, 0); + param->plugin->send_configure_change(); + param->gui->param_updated(); + return 1; +} + diff --git a/cinelerra-5.1/cinelerra/pluginclient.h b/cinelerra-5.1/cinelerra/pluginclient.h index 9ad0586d..96f5540b 100644 --- a/cinelerra-5.1/cinelerra/pluginclient.h +++ b/cinelerra-5.1/cinelerra/pluginclient.h @@ -161,10 +161,93 @@ public: virtual int translation_event(); virtual int close_event(); virtual void done_event(int result) {} +// A listener for PluginParam events + virtual void param_updated(); PluginClient *client; }; +// A GUI helper +class PluginFPot : public BC_FPot +{ +public: + PluginFPot(PluginParam *param, int x, int y); + int handle_event(); + PluginParam *param; +}; + +class PluginIPot : public BC_IPot +{ +public: + PluginIPot(PluginParam *param, int x, int y); + int handle_event(); + PluginParam *param; +}; + +class PluginQPot : public BC_QPot +{ +public: + PluginQPot(PluginParam *param, int x, int y); + int handle_event(); + PluginParam *param; +}; + +class PluginText : public BC_TextBox +{ +public: + PluginText(PluginParam *param, int x, int y, int value); + PluginText(PluginParam *param, int x, int y, float value); + int handle_event(); + PluginParam *param; +}; + +class PluginParam +{ +public: + PluginParam(PluginClient *plugin, + PluginClientWindow *gui, + int x1, + int x2, + int x3, + int y, + int text_w, + int *output_i, + float *output_f, // floating point output + int *output_q, // frequency output + const char *title, + float min, + float max); + ~PluginParam(); + + void initialize(); + void update(int skip_text, int skip_pot); +// set the number of fractional digits + void set_precision(int digits); + +// 2 possible outputs + float *output_f; + PluginFPot *fpot; + + int *output_i; + PluginIPot *ipot; + + int *output_q; + PluginQPot *qpot; + + char *title; + PluginText *text; + PluginClientWindow *gui; + PluginClient *plugin; + int x1; + int x2; + int x3; + int y; + int text_w; + float min; + float max; + int precision; +}; + diff --git a/cinelerra-5.1/cinelerra/pluginclient.inc b/cinelerra-5.1/cinelerra/pluginclient.inc index 82c15ac0..f9ee65b6 100644 --- a/cinelerra-5.1/cinelerra/pluginclient.inc +++ b/cinelerra-5.1/cinelerra/pluginclient.inc @@ -22,8 +22,15 @@ #ifndef PLUGINCLIENT_INC #define PLUGINCLIENT_INC -class PluginClient; -class PluginClientThread; +class PluginClientAuto; class PluginClientWindow; +class PluginFPot; +class PluginIPot; +class PluginQPot; +class PluginText; +class PluginParam; +class PluginClientThread; +class PluginClientFrame; +class PluginClient; #endif diff --git a/cinelerra-5.1/cinelerra/record.C b/cinelerra-5.1/cinelerra/record.C index 76990e67..4b8accd3 100644 --- a/cinelerra-5.1/cinelerra/record.C +++ b/cinelerra-5.1/cinelerra/record.C @@ -1829,10 +1829,7 @@ int Record::remote_process_key(RemoteControl *remote_control, int key) break; case 'f': { Canvas *canvas = record_monitor->window->canvas; - if( !canvas->get_fullscreen() ) - canvas->start_fullscreen(); - else - canvas->stop_fullscreen(); + canvas->use_fullscreen(canvas->get_fullscreen() ? 0 : 1); break; } default: return -1; diff --git a/cinelerra-5.1/cinelerra/vdevicex11.C b/cinelerra-5.1/cinelerra/vdevicex11.C index 8db5af1f..9a67d238 100644 --- a/cinelerra-5.1/cinelerra/vdevicex11.C +++ b/cinelerra-5.1/cinelerra/vdevicex11.C @@ -52,6 +52,7 @@ VDeviceX11::VDeviceX11(VideoDevice *device, Canvas *output) { reset_parameters(); this->output = output; + opened = 0; } VDeviceX11::~VDeviceX11() @@ -91,7 +92,7 @@ int VDeviceX11::open_input() capture_bitmap->bars_on(SCREENCAP_PIXELS, SCREENCAP_COLOR, device->input_x, device->input_y, device->in_config->w, device->in_config->h); - + opened = 1; return 0; } @@ -106,6 +107,7 @@ int VDeviceX11::open_output() else output->start_single(); } + opened = 1; output->unlock_canvas(); return 0; } @@ -126,6 +128,7 @@ int VDeviceX11::output_visible() int VDeviceX11::close_all() { + if( !opened ) return 1; if( output ) { BC_WindowBase *window = output->lock_canvas("VDeviceX11::close_all"); @@ -146,12 +149,12 @@ int VDeviceX11::close_all() delete bitmap; bitmap = 0; delete output_frame; output_frame = 0; delete capture_bitmap; capture_bitmap = 0; + opened = 0; if( output ) output->unlock_canvas(); reset_parameters(); - return 0; } diff --git a/cinelerra-5.1/cinelerra/vdevicex11.h b/cinelerra-5.1/cinelerra/vdevicex11.h index 223c474b..733a18a2 100644 --- a/cinelerra-5.1/cinelerra/vdevicex11.h +++ b/cinelerra-5.1/cinelerra/vdevicex11.h @@ -166,6 +166,7 @@ private: BC_Capture *capture_bitmap; // Set when OpenGL rendering has cleared the frame buffer before write_buffer int is_cleared; + int opened; }; #endif diff --git a/cinelerra-5.1/cinelerra/vwindowgui.C b/cinelerra-5.1/cinelerra/vwindowgui.C index 892fb050..8ecdb0d6 100644 --- a/cinelerra-5.1/cinelerra/vwindowgui.C +++ b/cinelerra-5.1/cinelerra/vwindowgui.C @@ -365,16 +365,13 @@ int VWindowGUI::keypress_event() break; case 'f': unlock_window(); - if( canvas->get_fullscreen() ) - canvas->stop_fullscreen(); - else - canvas->start_fullscreen(); + canvas->use_fullscreen(canvas->get_fullscreen() ? 0 : 1); lock_window("VWindowGUI::keypress_event 1"); break; case ESC: unlock_window(); if( canvas->get_fullscreen() ) - canvas->stop_fullscreen(); + canvas->use_fullscreen(0); lock_window("VWindowGUI::keypress_event 2"); break; case KEY_F1: @@ -815,6 +812,13 @@ void VWindowCanvas::zoom_resize_window(float percentage) gui->resize_event(new_w, new_h); } +void VWindowCanvas::zoom_auto() +{ + EDL *edl = gui->vwindow->get_edl(); + if(!edl) edl = mwindow->edl; + set_zoom(edl, 0); +} + void VWindowCanvas::close_source() { gui->vwindow->interrupt_playback(1); @@ -829,8 +833,9 @@ void VWindowCanvas::draw_refresh(int flush) if( !get_canvas()->get_video_on() ) { int cw = get_canvas()->get_w(), ch = get_canvas()->get_h(); get_canvas()->clear_box(0, 0, cw, ch); - int ow = get_output_w(edl), oh = get_output_h(edl); - if( ow > 0 && oh > 0 && refresh_frame && edl ) { + int ow = edl ? get_output_w(edl) : 0; + int oh = edl ? get_output_h(edl) : 0; + if( ow > 0 && oh > 0 && refresh_frame ) { float in_x1, in_y1, in_x2, in_y2; float out_x1, out_y1, out_x2, out_y2; get_transfers(edl, @@ -873,3 +878,14 @@ void VWindowCanvas::draw_overlays() } } +int VWindowCanvas::use_fullscreen(int on) +{ + if( Canvas::use_fullscreen(on) ) { + gui->lock_window("VWindowCanvas::use_fullscreen"); + zoom_auto(); + draw_refresh(1); + gui->unlock_window(); + } + return 1; +} + diff --git a/cinelerra-5.1/cinelerra/vwindowgui.h b/cinelerra-5.1/cinelerra/vwindowgui.h index d56df59e..d25df29c 100644 --- a/cinelerra-5.1/cinelerra/vwindowgui.h +++ b/cinelerra-5.1/cinelerra/vwindowgui.h @@ -94,8 +94,6 @@ public: VWindowOutPoint *out_point; char loaded_title[BCTEXTLEN]; int highlighted; -private: - void get_scrollbars(int &canvas_x, int &canvas_y, int &canvas_w, int &canvas_h); }; @@ -122,6 +120,8 @@ public: int need_overlays(); void draw_overlays(); void close_source(); + void zoom_auto(); + int use_fullscreen(int on); MWindow *mwindow; VWindowGUI *gui; diff --git a/cinelerra-5.1/cinelerra/zwindowgui.C b/cinelerra-5.1/cinelerra/zwindowgui.C index 1ffa772d..a52bad96 100644 --- a/cinelerra-5.1/cinelerra/zwindowgui.C +++ b/cinelerra-5.1/cinelerra/zwindowgui.C @@ -100,14 +100,10 @@ int ZWindowGUI::keypress_event() int result = 1; switch( key ) { case 'f': - if( canvas->get_fullscreen() ) - canvas->stop_fullscreen(); - else - canvas->start_fullscreen(); + canvas->use_fullscreen(canvas->get_fullscreen() ? 0 : 1); break; case ESC: - if( canvas->get_fullscreen() ) - canvas->stop_fullscreen(); + canvas->use_fullscreen(0); break; default: mwindow->gui->lock_window("ZWindowGUI::keypress_event"); @@ -248,3 +244,17 @@ void ZWindowCanvas::draw_refresh(int flush) cvs->flash(flush); } +float ZWindowCanvas::get_auto_zoom() +{ + EDL *edl = gui->zwindow->edl; + if( !edl ) edl = mwindow->edl; + float conformed_w, conformed_h; + edl->calculate_conformed_dimensions(0, conformed_w, conformed_h); + BC_WindowBase *window = get_canvas(); + int cw = window ? window->get_w() : w; + int ch = window ? window->get_h() : h; + float zoom_x = cw / conformed_w; + float zoom_y = ch / conformed_h; + return zoom_x < zoom_y ? zoom_x : zoom_y; +} + diff --git a/cinelerra-5.1/cinelerra/zwindowgui.h b/cinelerra-5.1/cinelerra/zwindowgui.h index 7604c4be..32bfd035 100644 --- a/cinelerra-5.1/cinelerra/zwindowgui.h +++ b/cinelerra-5.1/cinelerra/zwindowgui.h @@ -65,8 +65,9 @@ public: ZWindowCanvas(MWindow *mwindow, ZWindowGUI *gui, int x, int y, int w, int h); - void draw_refresh(int flush = 1); void close_source(); + void draw_refresh(int flush = 1); + float get_auto_zoom(); MWindow *mwindow; ZWindowGUI *gui; diff --git a/cinelerra-5.1/info/plugins.txt b/cinelerra-5.1/info/plugins.txt index 4acbaf7b..c56601c8 100644 --- a/cinelerra-5.1/info/plugins.txt +++ b/cinelerra-5.1/info/plugins.txt @@ -585,6 +585,7 @@ L_Bode frequency shifter (CV): Controls the frequency shift applied to the input signal, in KHz. L_Chebyshev distortion: Interesting distortion effect that is seeded from incoming signal envelope. +Chorus: Adds a chorus effect to the audio. L_Comb Filter: Controls the distance between the filters peaks. L_Comb Splitter: Divides the input up into two parts with frequency peaks at f Hz intervals, skewed by f/2 Hz between @@ -646,6 +647,7 @@ L_Fast Lookahead limiter: A limiter with an attack time of 5ms. It adds get the minimum amount of distortion. L_Fast overdrive: Compresses the extreme peaks to make a sound similar to an overdriven amplifier. +Flanger: Adds a flanger effect to the audio. L_Flanger: Digital flanger implementation. Uses excursion, controlled bandwidth modulation function, which makes the modulation less repetitive and noticable. @@ -785,6 +787,7 @@ Synthesizer: Generate synthesizer sounds; to set key data, turn L_Tape Delay Simulation: Models the tape motion and some smear effect. Time Stretch RT: Change the speed of an audio signal without affecting its pitch. +Tremolo: Applies a tremolo effect to the audio. #L_Transient mangler: #L_Triple band parametric with shelves: #L_Valve rectifier: diff --git a/cinelerra-5.1/plugin_defs b/cinelerra-5.1/plugin_defs index 50cf15aa..faff9ee0 100644 --- a/cinelerra-5.1/plugin_defs +++ b/cinelerra-5.1/plugin_defs @@ -127,6 +127,7 @@ plugin_dirs += audio audio := \ audioscope \ cdripper \ + chorus \ compressor \ dcoffset \ delayaudio \ @@ -136,6 +137,7 @@ audio := \ echo \ echocancel \ freeverb \ + flanger \ gain \ graphic \ interpolateaudio \ @@ -155,6 +157,7 @@ audio := \ synthesizer \ timestretch \ timestretchrt \ + tremolo \ vocoder \ plugin_dirs += opencv diff --git a/cinelerra-5.1/plugins/Makefile b/cinelerra-5.1/plugins/Makefile index 51b07190..2620b4d0 100644 --- a/cinelerra-5.1/plugins/Makefile +++ b/cinelerra-5.1/plugins/Makefile @@ -36,6 +36,7 @@ DIRS = $(OPENCV_OBJS) \ burn \ C41 \ cdripper \ + chorus \ chromakey \ chromakeyhsv \ color3way \ @@ -64,6 +65,7 @@ DIRS = $(OPENCV_OBJS) \ echo \ echocancel \ fieldframe \ + flanger \ flash \ flip \ framefield \ @@ -141,6 +143,7 @@ DIRS = $(OPENCV_OBJS) \ titler \ tracer \ translate \ + tremolo \ unsharp \ videoscope \ wave \ diff --git a/cinelerra-5.1/plugins/chorus/Makefile b/cinelerra-5.1/plugins/chorus/Makefile new file mode 100644 index 00000000..db5fea0e --- /dev/null +++ b/cinelerra-5.1/plugins/chorus/Makefile @@ -0,0 +1,9 @@ +include ../../plugin_defs + +OBJS = $(OBJDIR)/chorus.o + +PLUGIN = chorus + +include ../../plugin_config + +$(OBJDIR)/chorus.o: chorus.C diff --git a/cinelerra-5.1/plugins/chorus/chorus.C b/cinelerra-5.1/plugins/chorus/chorus.C new file mode 100644 index 00000000..6bf08c62 --- /dev/null +++ b/cinelerra-5.1/plugins/chorus/chorus.C @@ -0,0 +1,750 @@ + +/* + * CINELERRA + * Copyright (C) 2017-2019 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "chorus.h" +#include "clip.h" +#include "confirmsave.h" +#include "bchash.h" +#include "bcsignals.h" +#include "errorbox.h" +#include "filexml.h" +#include "language.h" +#include "samples.h" +#include "theme.h" +#include "transportque.inc" +#include "units.h" + +#include "vframe.h" + +#include +#include +#include +#include + + +// min rate for the GUI +#define MIN_RATE 0.0 +// min rate to avoid division by zero +#define MIN_RATE2 0.10 +#define MAX_RATE 10.0 +#define MIN_OFFSET 0.0 +#define MAX_OFFSET 100.0 +#define MIN_DEPTH 0.0 +#define MAX_DEPTH 100.0 +#define MIN_VOICES 1 +#define MAX_VOICES 64 + + + +PluginClient* new_plugin(PluginServer *server) +{ + return new Chorus(server); +} + + + +Chorus::Chorus(PluginServer *server) + : PluginAClient(server) +{ + srand(time(0)); + need_reconfigure = 1; + dsp_in = 0; + dsp_in_allocated = 0; + voices = 0; + last_position = -1; + flanging_table = 0; + table_size = 0; + history_buffer = 0; + history_size = 0; +} + +Chorus::~Chorus() +{ + if(dsp_in) + { + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { + delete [] dsp_in[i]; + } + delete [] dsp_in; + } + + if(history_buffer) + { + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { + delete [] history_buffer[i]; + } + delete [] history_buffer; + } + + delete [] voices; + delete [] flanging_table; +} + +const char* Chorus::plugin_title() { return N_("Chorus"); } +int Chorus::is_realtime() { return 1; } +int Chorus::is_multichannel() { return 1; } +int Chorus::is_synthesis() { return 1; } + + +int Chorus::process_buffer(int64_t size, + Samples **buffer, + int64_t start_position, + int sample_rate) +{ + need_reconfigure |= load_configuration(); +// printf("Chorus::process_buffer %d start_position=%ld size=%ld need_reconfigure=%d buffer_offset=%d\n", +// __LINE__, +// start_position, +// size, +// need_reconfigure, +// buffer[0]->get_offset()); + + + if(!dsp_in) + { + dsp_in = new double*[PluginClient::total_in_buffers]; + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { + dsp_in[i] = 0; + } + } + +// reset after seeking & configuring + if(last_position != start_position || need_reconfigure) + { + need_reconfigure = 0; + + if(flanging_table) + { + delete [] flanging_table; + } + +// flanging waveform is a whole number of samples that repeats + if(config.rate < MIN_RATE2) + { + table_size = 256; + } + else + { + table_size = (int)((double)sample_rate / config.rate); + if(table_size % 2) + { + table_size++; + } + } + + +// printf("Chorus::process_buffer %d table_size=%d\n", +// __LINE__, +// table_size); + + flanging_table = new flange_sample_t[table_size]; + double depth_samples = config.depth * + sample_rate / 1000; + double half_depth = depth_samples / 2; + int half_table = table_size / 2; + int quarter_table = table_size / 4; +// slow down over time to read from history buffer +// double ratio = (double)depth_samples / +// half; + double coef = (double)half_depth / + pow(quarter_table, 2); + +// printf("Chorus::process_buffer %d %f %f\n", +// __LINE__, +// depth_samples, +// sample_rate / 2 - depth_samples); + for(int i = 0; i <= quarter_table; i++) + { +// double input_sample = -i * ratio; + double input_sample = -(coef * pow(i, 2)); +// printf("Chorus::process_buffer %d i=%d input_sample=%f\n", +// __LINE__, +// i, +// input_sample); + flanging_table[i].input_sample = input_sample; + } + + for(int i = 0; i <= quarter_table; i++) + { + double input_sample = -depth_samples + + (coef * pow(quarter_table - i, 2)); +// printf("Chorus::process_buffer %d i=%d input_sample=%f\n", +// __LINE__, +// quarter_table + i, +// input_sample); + flanging_table[quarter_table + i].input_sample = input_sample; + } + +// rounding error may drop quarter_table * 2 + flanging_table[half_table].input_sample = -depth_samples; + + for(int i = 1; i < half_table; i++) + { + flanging_table[half_table + i].input_sample = + flanging_table[half_table - i].input_sample; +// printf("Chorus::process_buffer %d i=%d input_sample=%f\n", +// __LINE__, +// i, +// input_sample); + } + + +// dump the table +// for(int i = 0; i < table_size; i++) +// { +// printf("Chorus::process_buffer %d i=%d input_sample=%f\n", +// __LINE__, +// i, +// flanging_table[i].input_sample); +// } + + if(!history_buffer) + { + history_buffer = new double*[PluginClient::total_in_buffers]; + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { + history_buffer[i] = 0; + } + history_size = 0; + } + +// compute the phase position from the keyframe position & the phase offset + int64_t prev_position = edl_to_local( + get_prev_keyframe( + get_source_position())->position); + + if(prev_position == 0) + { + prev_position = get_source_start(); + } + + if(voices) + { + delete [] voices; + voices = 0; + } + + if(!voices) + { + voices = new Voice[total_voices()]; + } + + for(int i = 0; i < total_voices(); i++) + { + Voice *voice = &voices[i]; + voice->src_channel = i / config.voices; + voice->dst_channel = i % PluginClient::total_in_buffers; + +// randomize the starting phase + voice->table_offset = (int64_t)(start_position - + prev_position + + i * (table_size / 2) / total_voices()) % (table_size / 2); +// (rand() % (table_size / 2))) % (table_size / 2); +// printf("Chorus::process_buffer %d i=%d src=%d dst=%d input_sample=%f\n", +// __LINE__, +// i, +// voice->src_channel, +// voice->dst_channel, +// flanging_table[voice->table_offset].input_sample); + } + } + + int starting_offset = (int)(config.offset * sample_rate / 1000); + reallocate_dsp(size); +// reallocate_history(starting_offset + depth_offset + 1); +// always use the maximum history, in case of keyframes + reallocate_history((MAX_OFFSET + MAX_DEPTH) * sample_rate / 1000 + 1); + +// read the input + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { + read_samples(buffer[i], + i, + sample_rate, + start_position, + size); + } + + + +// paint the voices + double wetness = DB::fromdb(config.wetness); + if(config.wetness <= INFINITYGAIN) + { + wetness = 0; + } + +// input signal + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { + double *output = dsp_in[i]; + double *input = buffer[i]->get_data(); + for(int j = 0; j < size; j++) + { + output[j] = input[j] * wetness; + } + } + +// delayed signals + for(int i = 0; i < total_voices(); i++) + { + Voice *voice = &voices[i]; + double *output = dsp_in[voice->dst_channel]; + double *input = buffer[voice->src_channel]->get_data(); + double *history = history_buffer[voice->src_channel]; + +// printf("Chorus::process_buffer %d table_offset=%d table=%f\n", +// __LINE__, +// voice->table_offset, +// flanging_table[table_size / 2].input_sample); + +//static int debug = 1; + int table_offset = voice->table_offset; + for(int j = 0; j < size; j++) + { + flange_sample_t *table = &flanging_table[table_offset]; + double input_sample = j - starting_offset + table->input_sample; + +// values to interpolate + double sample1; + double sample2; + int input_sample1 = (int)(input_sample); + int input_sample2 = (int)(input_sample + 1); + double fraction1 = (double)((int)(input_sample + 1)) - input_sample; + double fraction2 = 1.0 - fraction1; + if(input_sample1 < 0) + { + sample1 = history[history_size + input_sample1]; + } + else + { + sample1 = input[input_sample1]; + } + + if(input_sample2 < 0) + { + sample2 = history[history_size + input_sample2]; + } + else + { + sample2 = input[input_sample2]; + } + output[j] += sample1 * fraction1 + sample2 * fraction2; +// if(start_position + j > 49600 && start_position + j < 49700) +// printf("%ld %d input_sample=%f sample1=%f sample2=%f output=%f\n", +// start_position + j, table_offset, input_sample, sample1, sample2, output[j]); + + if(config.rate >= MIN_RATE2) + { + table_offset++; + table_offset %= table_size; + } + } +//debug = 0; + voice->table_offset = table_offset; + } + + + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { +// history is bigger than input buffer. Copy entire input buffer. + if(history_size > size) + { + memcpy(history_buffer[i], + history_buffer[i] + size, + (history_size - size) * sizeof(double)); + memcpy(history_buffer[i] + (history_size - size), + buffer[i]->get_data(), + size * sizeof(double)); + } + else + { +// input is bigger than history buffer. Copy only history size + memcpy(history_buffer[i], + buffer[i]->get_data() + size - history_size, + history_size * sizeof(double)); + } + } +//printf("Chorus::process_buffer %d history_size=%ld\n", __LINE__, history_size); + +// copy the DSP buffer to the output + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { + memcpy(buffer[i]->get_data(), dsp_in[i], size * sizeof(double)); + } + + + if(get_direction() == PLAY_FORWARD) + { + last_position = start_position + size; + } + else + { + last_position = start_position - size; + } + + + + return 0; +} + + +int Chorus::total_voices() +{ + return PluginClient::total_in_buffers * config.voices; +} + + +void Chorus::reallocate_dsp(int new_dsp_allocated) +{ + if(new_dsp_allocated > dsp_in_allocated) + { +// copy samples already read into the new buffers + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { + double *old_dsp = dsp_in[i]; + double *new_dsp = new double[new_dsp_allocated]; + if(old_dsp) + { + delete [] old_dsp; + } + dsp_in[i] = new_dsp; + } + dsp_in_allocated = new_dsp_allocated; + } +} + +void Chorus::reallocate_history(int new_size) +{ + if(new_size != history_size) + { +// copy samples already read into the new buffers + for(int i = 0; i < PluginClient::total_in_buffers; i++) + { + double *old_history = 0; + + if(history_buffer) + { + old_history = history_buffer[i]; + } + double *new_history = new double[new_size]; + bzero(new_history, sizeof(double) * new_size); + if(old_history) + { + int copy_size = MIN(new_size, history_size); + memcpy(new_history, + old_history + history_size - copy_size, + sizeof(double) * copy_size); + delete [] old_history; + } + history_buffer[i] = new_history; + } + history_size = new_size; + } +} + + + + + +NEW_WINDOW_MACRO(Chorus, ChorusWindow) + + +LOAD_CONFIGURATION_MACRO(Chorus, ChorusConfig) + + +void Chorus::save_data(KeyFrame *keyframe) +{ + FileXML output; + +// cause xml file to store data directly in text + output.set_shared_output(keyframe->xbuf); + + output.tag.set_title("CHORUS"); + output.tag.set_property("VOICES", config.voices); + output.tag.set_property("OFFSET", config.offset); + output.tag.set_property("DEPTH", config.depth); + output.tag.set_property("RATE", config.rate); + output.tag.set_property("WETNESS", config.wetness); + output.append_tag(); + output.append_newline(); + + output.terminate_string(); +} + +void Chorus::read_data(KeyFrame *keyframe) +{ + FileXML input; +// cause xml file to read directly from text + input.set_shared_input(keyframe->xbuf); + int result = 0; + + result = input.read_tag(); + + if(!result) + { + if(input.tag.title_is("CHORUS")) + { + config.voices = input.tag.get_property("VOICES", config.voices); + config.offset = input.tag.get_property("OFFSET", config.offset); + config.depth = input.tag.get_property("DEPTH", config.depth); + config.rate = input.tag.get_property("RATE", config.rate); + config.wetness = input.tag.get_property("WETNESS", config.wetness); + } + } + + config.boundaries(); +} + +void Chorus::update_gui() +{ + if(thread) + { + if(load_configuration()) + { + thread->window->lock_window("Chorus::update_gui 1"); + ((ChorusWindow*)thread->window)->update(); + thread->window->unlock_window(); + } + } +} + + + + + + + + +Voice::Voice() +{ +} + + + +ChorusConfig::ChorusConfig() +{ + voices = 1; + offset = 0.00; + depth = 10.0; + rate = 0.20; + wetness = 0; +} + +int ChorusConfig::equivalent(ChorusConfig &that) +{ + return (voices == that.voices) && + EQUIV(offset, that.offset) && + EQUIV(depth, that.depth) && + EQUIV(rate, that.rate) && + EQUIV(wetness, that.wetness); +} + +void ChorusConfig::copy_from(ChorusConfig &that) +{ + voices = that.voices; + offset = that.offset; + depth = that.depth; + rate = that.rate; + wetness = that.wetness; +} + +void ChorusConfig::interpolate(ChorusConfig &prev, + ChorusConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame) +{ + copy_from(prev); +} + +void ChorusConfig::boundaries() +{ + CLAMP(voices, MIN_VOICES, MAX_VOICES); + CLAMP(offset, MIN_OFFSET, MAX_OFFSET); + CLAMP(depth, MIN_DEPTH, MAX_DEPTH); + CLAMP(rate, MIN_RATE, MAX_RATE); + CLAMP(wetness, INFINITYGAIN, 0.0); +} + + + + + + + + + + + +#define WINDOW_W xS(400) +#define WINDOW_H yS(165) + +ChorusWindow::ChorusWindow(Chorus *plugin) + : PluginClientWindow(plugin, + WINDOW_W, + WINDOW_H, + WINDOW_W, + WINDOW_H, + 0) +{ + this->plugin = plugin; +} + +ChorusWindow::~ChorusWindow() +{ + delete voices; + delete offset; + delete depth; + delete rate; + delete wetness; +} + +void ChorusWindow::create_objects() +{ + int margin = plugin->get_theme()->widget_border + xS(4); + int x1 = margin; + int x2 = xS(200), y = margin -xS(4); + int x3 = x2 + BC_Pot::calculate_w() + margin; + int x4 = x3 + BC_Pot::calculate_w() + margin; + int text_w = get_w() - margin - x4; + int height = BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1) + margin -xS(4); + + + voices = new PluginParam(plugin, + this, + x1, + x2, + x4, + y, + text_w, + &plugin->config.voices, // output_i + 0, // output_f + 0, // output_q + "Voices per channel:", + MIN_VOICES, // min + MAX_VOICES); // max + voices->initialize(); + y += height; + + offset = new PluginParam(plugin, + this, + x1, + x3, + x4, + y, + text_w, + 0, // output_i + &plugin->config.offset, // output_f + 0, // output_q + "Phase offset (ms):", + MIN_OFFSET, // min + MAX_OFFSET); // max + offset->set_precision(3); + offset->initialize(); + y += height; + + + depth = new PluginParam(plugin, + this, + x1, + x2, + x4, + y, + text_w, + 0, // output_i + &plugin->config.depth, // output_f + 0, // output_q + "Depth (ms):", + MIN_DEPTH, // min + MAX_DEPTH); // max + depth->set_precision(3); + depth->initialize(); + y += height; + + + + rate = new PluginParam(plugin, + this, + x1, + x3, + x4, + y, + text_w, + 0, // output_i + &plugin->config.rate, // output_f + 0, // output_q + "Rate (Hz):", + MIN_RATE, // min + MAX_RATE); // max + rate->set_precision(3); + rate->initialize(); + y += height; + + + + wetness = new PluginParam(plugin, + this, + x1, + x2, + x4, + y, + text_w, + 0, // output_i + &plugin->config.wetness, // output_f + 0, // output_q + "Wetness (db):", + INFINITYGAIN, // min + 0); // max + wetness->initialize(); + y += height; + + show_window(); +} + +void ChorusWindow::update() +{ + voices->update(0, 0); + offset->update(0, 0); + depth->update(0, 0); + rate->update(0, 0); + wetness->update(0, 0); +} + +void ChorusWindow::param_updated() +{ +} + + + + + + + + + + + + + diff --git a/cinelerra-5.1/plugins/chorus/chorus.h b/cinelerra-5.1/plugins/chorus/chorus.h new file mode 100644 index 00000000..0cb40084 --- /dev/null +++ b/cinelerra-5.1/plugins/chorus/chorus.h @@ -0,0 +1,152 @@ + +/* + * CINELERRA + * Copyright (C) 2008-2019 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef CHORUS_H +#define CHORUS_H + +class Chorus; + +#include "pluginaclient.h" + +class ChorusConfig +{ +public: + ChorusConfig(); + + + int equivalent(ChorusConfig &that); + void copy_from(ChorusConfig &that); + void interpolate(ChorusConfig &prev, + ChorusConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame); + void boundaries(); + + +// number of voices per channel to be rendered + int voices; +// starting phase offset in ms + float offset; +// how much the phase oscillates in ms + float depth; +// rate of phase oscillation in Hz + float rate; +// how much of input signal + float wetness; +}; + +// state of a single voice +class Voice +{ +public: + Voice(); + +// position in the waveform table + int table_offset; +// source channel + int src_channel; +// destination channel + int dst_channel; +}; + + +// each sample in the flanging waveform +typedef struct +{ + double input_sample; +} flange_sample_t; + + +class Chorus : public PluginAClient +{ +public: + Chorus(PluginServer *server); + ~Chorus(); + + void update_gui(); + + + +// required for all realtime/multichannel plugins + PLUGIN_CLASS_MEMBERS(ChorusConfig); + int process_buffer(int64_t size, + Samples **buffer, + int64_t start_position, + int sample_rate); + void reallocate_dsp(int new_dsp_allocated); + void reallocate_history(int new_allocation); + int total_voices(); + + int is_realtime(); + int is_synthesis(); + int is_multichannel(); + void save_data(KeyFrame *keyframe); + void read_data(KeyFrame *keyframe); + + double **history_buffer; +// Number of samples in the history buffer + int64_t history_size; + +// the temporary all voices are painted on + double **dsp_in; + int dsp_in_allocated; + + Voice *voices; +// flanging table is a whole number of samples that repeats +// always an even number + int table_size; + flange_sample_t *flanging_table; + +// detect seeking + int64_t last_position; + + int need_reconfigure; +}; + + + + +class ChorusWindow : public PluginClientWindow +{ +public: + ChorusWindow(Chorus *plugin); + ~ChorusWindow(); + + void create_objects(); + void update(); + void param_updated(); + + Chorus *plugin; + PluginParam *voices; + PluginParam *offset; + PluginParam *depth; + PluginParam *rate; + PluginParam *wetness; +}; + + + + +#endif + + + diff --git a/cinelerra-5.1/plugins/flanger/Makefile b/cinelerra-5.1/plugins/flanger/Makefile new file mode 100644 index 00000000..ce6d73fd --- /dev/null +++ b/cinelerra-5.1/plugins/flanger/Makefile @@ -0,0 +1,9 @@ +include ../../plugin_defs + +OBJS = $(OBJDIR)/flanger.o + +PLUGIN = flanger + +include ../../plugin_config + +$(OBJDIR)/flanger.o: flanger.C diff --git a/cinelerra-5.1/plugins/flanger/flanger.C b/cinelerra-5.1/plugins/flanger/flanger.C new file mode 100644 index 00000000..da5752f9 --- /dev/null +++ b/cinelerra-5.1/plugins/flanger/flanger.C @@ -0,0 +1,598 @@ + +/* + * CINELERRA + * Copyright (C) 2017-2019 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "clip.h" +#include "bcdisplayinfo.h" +#include "bchash.h" +#include "bcsignals.h" +#include "filexml.h" +#include "flanger.h" +#include "guicast.h" +#include "language.h" +#include "samples.h" +#include "theme.h" +#include "transportque.inc" +#include "units.h" + + +#include +#include +#include +#include + + +#define MIN_RATE 0.1 +#define MAX_RATE 10.0 +#define MIN_OFFSET 0.0 +#define MAX_OFFSET 100.0 +#define MIN_DEPTH 0.0 +#define MAX_DEPTH 100.0 +#define MIN_STARTING_PHASE 0 +#define MAX_STARTING_PHASE 100 + + +PluginClient* new_plugin(PluginServer *server) +{ + return new Flanger(server); +} + + + +Flanger::Flanger(PluginServer *server) + : PluginAClient(server) +{ + need_reconfigure = 1; + dsp_in = 0; + dsp_in_allocated = 0; + last_position = -1; + flanging_table = 0; + table_size = 0; + history_buffer = 0; + history_size = 0; +} + +Flanger::~Flanger() +{ + if(dsp_in) + { + delete [] dsp_in; + } + + if(history_buffer) + { + delete [] history_buffer; + } + + delete [] flanging_table; +} + +const char* Flanger::plugin_title() { return N_("Flanger"); } +int Flanger::is_realtime() { return 1; } +int Flanger::is_multichannel() { return 0; } +int Flanger::is_synthesis() { return 0; } +// phyllis VFrame* Flanger::new_picon() { return 0; } + + +int Flanger::process_buffer(int64_t size, + Samples *buffer, + int64_t start_position, + int sample_rate) +{ + need_reconfigure |= load_configuration(); +// printf("Flanger::process_buffer %d start_position=%ld size=%ld\n", +// __LINE__, +// start_position, +// size); + + + +// reset after seeking & configuring + if(last_position != start_position || need_reconfigure) + { + need_reconfigure = 0; + + if(flanging_table) + { + delete [] flanging_table; + } + +// flanging waveform is a whole number of samples that repeats + table_size = (int)((double)sample_rate / config.rate); + if(table_size % 2) + { + table_size++; + } + + flanging_table = new flange_sample_t[table_size]; + double depth_samples = config.depth * + sample_rate / 1000; +// read behind so the flange can work in realtime + double ratio = (double)depth_samples / + (table_size / 2); +// printf("Flanger::process_buffer %d %f %f\n", +// __LINE__, +// depth_samples, +// sample_rate / 2 - depth_samples); + for(int i = 0; i <= table_size / 2; i++) + { + double input_sample = -i * ratio; +// printf("Flanger::process_buffer %d i=%d input_sample=%f ratio=%f\n", +// __LINE__, +// i, +// input_sample, +// ratio); + flanging_table[i].input_sample = input_sample; + flanging_table[i].input_period = ratio; + } + + for(int i = table_size / 2 + 1; i < table_size; i++) + { + double input_sample = -ratio * (table_size - i); + flanging_table[i].input_sample = input_sample; + flanging_table[i].input_period = ratio; +// printf("Flanger::process_buffer %d i=%d input_sample=%f ratio=%f\n", +// __LINE__, +// i, +// input_sample, +// ratio); + } + + + +// compute the phase position from the keyframe position & the phase offset + int64_t prev_position = edl_to_local( + get_prev_keyframe( + get_source_position())->position); + + if(prev_position == 0) + { + prev_position = get_source_start(); + } + + voice.table_offset = (int64_t)(start_position - + prev_position + + config.starting_phase * table_size / 100) % table_size; +// printf("Flanger::process_buffer %d start_position=%ld table_offset=%d table_size=%d\n", +// __LINE__, +// start_position, +// voice.table_offset, +// table_size); + } + + int starting_offset = (int)(config.offset * sample_rate / 1000); +//phyllis int depth_offset = (int)(config.depth * sample_rate / 1000); + reallocate_dsp(size); +// reallocate_history(starting_offset + depth_offset + 1); +// always use the maximum history, in case of keyframes + reallocate_history((MAX_OFFSET + MAX_DEPTH) * sample_rate / 1000 + 1); + +// read the input + read_samples(buffer, + 0, + sample_rate, + start_position, + size); + + + +// paint the voices + double wetness = DB::fromdb(config.wetness); + if(config.wetness <= INFINITYGAIN) + { + wetness = 0; + } + + double *output = dsp_in; + double *input = buffer->get_data(); + +// input signal + for(int j = 0; j < size; j++) + { + output[j] = input[j] * wetness; + } + + +// delayed signal + int table_offset = voice.table_offset; + for(int j = 0; j < size; j++) + { + flange_sample_t *table = &flanging_table[table_offset]; + double input_sample = j - starting_offset + table->input_sample; +//phyllis double input_period = table->input_period; + +// if(j == 0) +// printf("Flanger::process_buffer %d input_sample=%f\n", +// __LINE__, +// input_sample); + +// values to interpolate + double sample1; + double sample2; + int input_sample1 = (int)(input_sample); + int input_sample2 = (int)(input_sample + 1); + double fraction1 = (double)((int)(input_sample + 1)) - input_sample; + double fraction2 = 1.0 - fraction1; + if(input_sample1 < 0) + { + sample1 = history_buffer[history_size + input_sample1]; + } + else + { + sample1 = input[input_sample1]; + } + + if(input_sample2 < 0) + { + sample2 = history_buffer[history_size + input_sample2]; + } + else + { + sample2 = input[input_sample2]; + } + output[j] += sample1 * fraction1 + sample2 * fraction2; + + table_offset++; + table_offset %= table_size; + } + voice.table_offset = table_offset; + +// history is bigger than input buffer. Copy entire input buffer. + if(history_size > size) + { + memcpy(history_buffer, + history_buffer + size, + (history_size - size) * sizeof(double)); + memcpy(history_buffer + (history_size - size), + buffer->get_data(), + size * sizeof(double)); + } + else + { +// input is bigger than history buffer. Copy only history size + memcpy(history_buffer, + buffer->get_data() + size - history_size, + history_size * sizeof(double)); + } +//printf("Flanger::process_buffer %d\n", +//__LINE__); + + +// copy the DSP buffer to the output + memcpy(buffer->get_data(), dsp_in, size * sizeof(double)); + + + if(get_direction() == PLAY_FORWARD) + { + last_position = start_position + size; + } + else + { + last_position = start_position - size; + } + + + + return 0; +} + + +void Flanger::reallocate_dsp(int new_dsp_allocated) +{ + if(new_dsp_allocated > dsp_in_allocated) + { + if(dsp_in) + { + delete [] dsp_in; + } + dsp_in = new double[new_dsp_allocated]; + dsp_in_allocated = new_dsp_allocated; + } +} + +void Flanger::reallocate_history(int new_size) +{ + if(new_size != history_size) + { +// copy samples already read into the new buffers + double *new_history = new double[new_size]; + bzero(new_history, sizeof(double) * new_size); + if(history_buffer) + { + int copy_size = MIN(new_size, history_size); + memcpy(new_history, + history_buffer + history_size - copy_size, + sizeof(double) * copy_size); + delete [] history_buffer; + } + history_buffer = new_history; + history_size = new_size; + } +} + + +NEW_WINDOW_MACRO(Flanger, FlangerWindow) +LOAD_CONFIGURATION_MACRO(Flanger, FlangerConfig) + + +void Flanger::save_data(KeyFrame *keyframe) +{ + FileXML output; + +// cause xml file to store data directly in text + output.set_shared_output(keyframe->xbuf); + + output.tag.set_title("FLANGER"); + output.tag.set_property("OFFSET", config.offset); + output.tag.set_property("STARTING_PHASE", config.starting_phase); + output.tag.set_property("DEPTH", config.depth); + output.tag.set_property("RATE", config.rate); + output.tag.set_property("WETNESS", config.wetness); + output.append_tag(); + output.append_newline(); + + + + output.terminate_string(); +} + +void Flanger::read_data(KeyFrame *keyframe) +{ + FileXML input; +// cause xml file to read directly from text + input.set_shared_input(keyframe->xbuf); + int result = 0; + + result = input.read_tag(); + + if(!result) + { + if(input.tag.title_is("FLANGER")) + { + config.offset = input.tag.get_property("OFFSET", config.offset); + config.starting_phase = input.tag.get_property("STARTING_PHASE", config.starting_phase); + config.depth = input.tag.get_property("DEPTH", config.depth); + config.rate = input.tag.get_property("RATE", config.rate); + config.wetness = input.tag.get_property("WETNESS", config.wetness); + } + } + + config.boundaries(); +} + +void Flanger::update_gui() +{ + if(thread) + { + if(load_configuration()) + { + thread->window->lock_window("Flanger::update_gui 1"); + ((FlangerWindow*)thread->window)->update(); + thread->window->unlock_window(); + } + } +} + + + + +Voice::Voice() +{ +} + + + + + + +FlangerConfig::FlangerConfig() +{ + offset = 0.00; + starting_phase = 0; + depth = 10.0; + rate = 0.20; + wetness = 0; +} + +int FlangerConfig::equivalent(FlangerConfig &that) +{ + return EQUIV(offset, that.offset) && + EQUIV(starting_phase, that.starting_phase) && + EQUIV(depth, that.depth) && + EQUIV(rate, that.rate) && + EQUIV(wetness, that.wetness); +} + +void FlangerConfig::copy_from(FlangerConfig &that) +{ + offset = that.offset; + starting_phase = that.starting_phase; + depth = that.depth; + rate = that.rate; + wetness = that.wetness; +} + +void FlangerConfig::interpolate(FlangerConfig &prev, + FlangerConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame) +{ + copy_from(prev); +} + +void FlangerConfig::boundaries() +{ + CLAMP(offset, MIN_OFFSET, MAX_OFFSET); + CLAMP(starting_phase, MIN_STARTING_PHASE, MAX_STARTING_PHASE); + CLAMP(depth, MIN_DEPTH, MAX_DEPTH); + CLAMP(rate, MIN_RATE, MAX_RATE); + CLAMP(wetness, INFINITYGAIN, 0.0); +} + + + + + + + + +#define WINDOW_W xS(400) +#define WINDOW_H yS(165) + +FlangerWindow::FlangerWindow(Flanger *plugin) + : PluginClientWindow(plugin, + WINDOW_W, + WINDOW_H, + WINDOW_W, + WINDOW_H, + 0) +{ + this->plugin = plugin; +} + +FlangerWindow::~FlangerWindow() +{ + delete offset; + delete starting_phase; + delete depth; + delete rate; + delete wetness; +} + +void FlangerWindow::create_objects() +{ + int margin = client->get_theme()->widget_border + xS(4); + int x1 = margin; + int x2 = xS(200), y = margin - xS(4); + int x3 = x2 + BC_Pot::calculate_w() + margin; + int x4 = x3 + BC_Pot::calculate_w() + margin; + int text_w = get_w() - margin - x4; + int height = BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1) + margin - xS(4); + + + offset = new PluginParam(plugin, + this, + x1, + x3, + x4, + y, + text_w, + 0, // output_i + &plugin->config.offset, // output_f + 0, // output_q + "Phase offset (ms):", + MIN_OFFSET, // min + MAX_OFFSET); // max + offset->set_precision(3); + offset->initialize(); + y += height; + + + starting_phase = new PluginParam(plugin, + this, + x1, + x2, + x4, + y, + text_w, + 0, // output_i + &plugin->config.starting_phase, // output_f + 0, // output_q + "Starting phase (%):", + MIN_STARTING_PHASE, // min + MAX_STARTING_PHASE); // max + starting_phase->set_precision(3); + starting_phase->initialize(); + y += height; + + + + depth = new PluginParam(plugin, + this, + x1, + x3, + x4, + y, + text_w, + 0, // output_i + &plugin->config.depth, // output_f + 0, // output_q + "Depth (ms):", + MIN_DEPTH, // min + MAX_DEPTH); // max + depth->set_precision(3); + depth->initialize(); + y += height; + + + + rate = new PluginParam(plugin, + this, + x1, + x2, + x4, + y, + text_w, + 0, // output_i + &plugin->config.rate, // output_f + 0, // output_q + "Rate (Hz):", + MIN_RATE, // min + MAX_RATE); // max + rate->set_precision(3); + rate->initialize(); + y += height; + + + + wetness = new PluginParam(plugin, + this, + x1, + x3, + x4, + y, + text_w, + 0, // output_i + &plugin->config.wetness, // output_f + 0, // output_q + "Wetness (db):", + INFINITYGAIN, // min + 0); // max + wetness->set_precision(3); + wetness->initialize(); + y += height; + + show_window(); +} + +void FlangerWindow::update() +{ + offset->update(0, 0); + starting_phase->update(0, 0); + depth->update(0, 0); + rate->update(0, 0); + wetness->update(0, 0); +} + +void FlangerWindow::param_updated() +{ +} + diff --git a/cinelerra-5.1/plugins/flanger/flanger.h b/cinelerra-5.1/plugins/flanger/flanger.h new file mode 100644 index 00000000..d41c1de4 --- /dev/null +++ b/cinelerra-5.1/plugins/flanger/flanger.h @@ -0,0 +1,148 @@ + +/* + * CINELERRA + * Copyright (C) 2008-2019 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef FLANGER_H +#define FLANGER_H + +class Flanger; + +#include "pluginaclient.h" + + +class FlangerConfig +{ +public: + FlangerConfig(); + + + int equivalent(FlangerConfig &that); + void copy_from(FlangerConfig &that); + void interpolate(FlangerConfig &prev, + FlangerConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame); + void boundaries(); + +// phase offset in ms + float offset; +// starting position of oscillation in % + float starting_phase; +// how much the phase oscillates in ms + float depth; +// rate of phase oscillation in Hz + float rate; +// how much of input signal + float wetness; +}; + + +// state of a single voice +class Voice +{ +public: + Voice(); + +// position in the waveform table + int table_offset; +}; + +// each sample in the flanging waveform +typedef struct +{ + double input_sample; + double input_period; +} flange_sample_t; + +class Flanger : public PluginAClient +{ +public: + Flanger(PluginServer *server); + ~Flanger(); + + void update_gui(); + + + +// required for all realtime/multichannel plugins + PLUGIN_CLASS_MEMBERS(FlangerConfig); + int process_buffer(int64_t size, + Samples *buffer, + int64_t start_position, + int sample_rate); + void reallocate_dsp(int new_dsp_allocated); + void reallocate_history(int new_allocation); + + int is_realtime(); + int is_synthesis(); + int is_multichannel(); + void save_data(KeyFrame *keyframe); + void read_data(KeyFrame *keyframe); + + double *history_buffer; +// Number of samples in the history buffer + int64_t history_size; + +// the temporary all voices are painted on + double *dsp_in; + int dsp_in_allocated; + + Voice voice; +// flanging table is a whole number of samples that repeats +// always an even number + int table_size; + flange_sample_t *flanging_table; + +// detect seeking + int64_t last_position; + + int need_reconfigure; +}; + + + + + +class FlangerWindow : public PluginClientWindow +{ +public: + FlangerWindow(Flanger *plugin); + ~FlangerWindow(); + + void create_objects(); + void update(); + void param_updated(); + + Flanger *plugin; + PluginParam *offset; + PluginParam *starting_phase; + PluginParam *depth; + PluginParam *rate; + PluginParam *wetness; +}; + + + + +#endif + + + diff --git a/cinelerra-5.1/plugins/tremolo/Makefile b/cinelerra-5.1/plugins/tremolo/Makefile new file mode 100644 index 00000000..405282f5 --- /dev/null +++ b/cinelerra-5.1/plugins/tremolo/Makefile @@ -0,0 +1,9 @@ +include ../../plugin_defs + +OBJS = $(OBJDIR)/tremolo.o + +PLUGIN = tremolo + +include ../../plugin_config + +$(OBJDIR)/tremolo.o: tremolo.C diff --git a/cinelerra-5.1/plugins/tremolo/tremolo.C b/cinelerra-5.1/plugins/tremolo/tremolo.C new file mode 100644 index 00000000..99799e73 --- /dev/null +++ b/cinelerra-5.1/plugins/tremolo/tremolo.C @@ -0,0 +1,539 @@ + +/* + * CINELERRA + * Copyright (C) 2017-2019 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "clip.h" +#include "confirmsave.h" +#include "bchash.h" +#include "bcsignals.h" +#include "errorbox.h" +#include "filexml.h" +#include "language.h" +#include "samples.h" +#include "theme.h" +#include "transportque.inc" +#include "tremolo.h" +#include "units.h" + +#include "vframe.h" + +#include +#include +#include +#include + + +// min rate for the GUI +#define MIN_RATE 0.0 +// min rate to avoid division by zero +#define MIN_RATE2 0.10 +#define MAX_RATE 10.0 +#define MIN_OFFSET 0.0 +#define MAX_OFFSET 100.0 +#define MIN_DEPTH 0.0 +#define MAX_DEPTH (-INFINITYGAIN) + + + +PluginClient* new_plugin(PluginServer *server) +{ + return new Tremolo(server); +} + + + +Tremolo::Tremolo(PluginServer *server) + : PluginAClient(server) +{ + need_reconfigure = 1; + table = 0; + table_size = 0; + table_offset = 0; + last_position = 0; +} + +Tremolo::~Tremolo() +{ + delete [] table; +} + +const char* Tremolo::plugin_title() { return N_("Tremolo"); } +int Tremolo::is_realtime() { return 1; } +int Tremolo::is_multichannel() { return 0; } +int Tremolo::is_synthesis() { return 0; } + + +int Tremolo::process_buffer(int64_t size, + Samples *buffer, + int64_t start_position, + int sample_rate) +{ + need_reconfigure |= load_configuration(); +// printf("Tremolo::process_buffer %d start_position=%ld size=%ld need_reconfigure=%d\n", +// __LINE__, +// start_position, +// size, +// need_reconfigure); + +// reset after configuring + if(last_position != start_position || + need_reconfigure) + { + need_reconfigure = 0; + + if(table) + { + delete [] table; + } + +// waveform is a whole number of samples that repeats + if(config.rate < MIN_RATE2) + { + table_size = 256; + } + else + { + table_size = (int)((double)sample_rate / config.rate); + } + + + table = new double[table_size]; + double depth = 1.0 - DB::fromdb(-config.depth); + +// printf("Tremolo::process_buffer %d table_size=%d depth=%f\n", +// __LINE__, +// table_size, +// depth); + + for(int i = 0; i < table_size; i++) + { + double value = 0; + + switch(config.waveform) + { + case SINE: + value = (sin((double)i * 2 * M_PI / table_size + 3.0 * M_PI / 2) + 1) / 2; + break; + case SAWTOOTH: + value = (double)(table_size - i) / table_size; + break; + case SAWTOOTH2: + value = (double)i / table_size; + break; + case SQUARE: + if(i < table_size / 2) + { + value = 0; + } + else + { + value = 1; + } + break; + case TRIANGLE: + if(i < table_size / 2) + { + value = (double)(i * 2) / table_size; + } + else + { + value = 1.0 - + (double)(i - table_size / 2) / + (table_size / 2); + } + break; + } +// value is -1 ... 0 + value = 1.0 - value * depth; +// printf("Tremolo::process_buffer %d i=%d value=%f\n", +// __LINE__, +// i, +// value); + table[i] = value; + } + + +// compute the phase position from the keyframe position & the phase offset + int64_t prev_position = edl_to_local( + get_prev_keyframe( + get_source_position())->position); + + if(prev_position == 0) + { + prev_position = get_source_start(); + } + + int64_t starting_offset = (int64_t)(config.offset * table_size / 100); + table_offset = (int64_t)(start_position - + prev_position + + starting_offset) % + table_size; +// printf("Tremolo::process_buffer %d table_offet=%d table_size=%d\n", +// __LINE__, +// table_offset, +// table_size); + +// printf("Tremolo::process_buffer %d i=%d src=%d dst=%d input_sample=%f\n", +// __LINE__, +// i, +// voice->src_channel, +// voice->dst_channel, +// flanging_table[voice->table_offset].input_sample); + } + + +// read the input + read_samples(buffer, + 0, + sample_rate, + start_position, + size); + +// input signal + double *in = buffer->get_data(); + double *out = buffer->get_data(); + for(int j = 0; j < size; j++) + { + out[j] = in[j] * table[table_offset++]; + table_offset %= table_size; + } + + + + if(get_direction() == PLAY_FORWARD) + { + last_position = start_position + size; + } + else + { + last_position = start_position - size; + } +//printf("Tremolo::process_buffer %d\n", __LINE__); + + + + return 0; +} + + + +NEW_WINDOW_MACRO(Tremolo, TremoloWindow) + + +LOAD_CONFIGURATION_MACRO(Tremolo, TremoloConfig) + + +void Tremolo::save_data(KeyFrame *keyframe) +{ + FileXML output; + +// cause xml file to store data directly in text + output.set_shared_output(keyframe->xbuf); + + output.tag.set_title("TREMOLO"); + output.tag.set_property("OFFSET", config.offset); + output.tag.set_property("DEPTH", config.depth); + output.tag.set_property("RATE", config.rate); + output.tag.set_property("WAVEFORM", config.waveform); + output.append_tag(); + output.append_newline(); + + output.terminate_string(); +} + +void Tremolo::read_data(KeyFrame *keyframe) +{ + FileXML input; +// cause xml file to read directly from text + input.set_shared_input(keyframe->xbuf); + int result = 0; + + result = input.read_tag(); + + if(!result) + { + if(input.tag.title_is("TREMOLO")) + { + config.offset = input.tag.get_property("OFFSET", config.offset); + config.depth = input.tag.get_property("DEPTH", config.depth); + config.rate = input.tag.get_property("RATE", config.rate); + config.waveform = input.tag.get_property("WAVEFORM", config.waveform); + } + } + + config.boundaries(); +} + +void Tremolo::update_gui() +{ + if(thread) + { + if(load_configuration()) + { + thread->window->lock_window("Tremolo::update_gui 1"); + ((TremoloWindow*)thread->window)->update(); + thread->window->unlock_window(); + } + } +} + + + + + + + + + +TremoloConfig::TremoloConfig() +{ + offset = 0.00; + depth = 10.0; + rate = 0.20; + waveform = SINE; +} + +int TremoloConfig::equivalent(TremoloConfig &that) +{ + return EQUIV(offset, that.offset) && + EQUIV(depth, that.depth) && + EQUIV(rate, that.rate) && + waveform == that.waveform; +} + +void TremoloConfig::copy_from(TremoloConfig &that) +{ + offset = that.offset; + depth = that.depth; + rate = that.rate; + waveform = that.waveform; +} + +void TremoloConfig::interpolate(TremoloConfig &prev, + TremoloConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame) +{ + copy_from(prev); +} + +void TremoloConfig::boundaries() +{ + CLAMP(offset, MIN_OFFSET, MAX_OFFSET); + CLAMP(depth, MIN_DEPTH, MAX_DEPTH); + CLAMP(rate, MIN_RATE, MAX_RATE); + CLAMP(waveform, 0, TOTAL_WAVEFORMS - 1); +} + + + + + + + + + + + +#define WINDOW_W xS(400) +#define WINDOW_H yS(140) + +TremoloWindow::TremoloWindow(Tremolo *plugin) + : PluginClientWindow(plugin, + WINDOW_W, + WINDOW_H, + WINDOW_W, + WINDOW_H, + 0) +{ + this->plugin = plugin; +} + +TremoloWindow::~TremoloWindow() +{ + delete offset; + delete depth; + delete rate; + delete waveform; +} + +void TremoloWindow::create_objects() +{ + int margin = plugin->get_theme()->widget_border + xS(4); + int x1 = margin; + int x2 = xS(200), y = margin - xS(4); + int x3 = x2 + BC_Pot::calculate_w() + margin; + int x4 = x3 + BC_Pot::calculate_w() + margin; + int text_w = get_w() - margin - x4; + int height = BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1) + margin - xS(4); + + + offset = new PluginParam(plugin, + this, + x1, + x3, + x4, + y, + text_w, + 0, // output_i + &plugin->config.offset, // output_f + 0, // output_q + "Phase offset (%):", + MIN_OFFSET, // min + MAX_OFFSET); // max + offset->set_precision(3); + offset->initialize(); + y += height; + + + depth = new PluginParam(plugin, + this, + x1, + x2, + x4, + y, + text_w, + 0, // output_i + &plugin->config.depth, // output_f + 0, // output_q + "Depth (dB):", + MIN_DEPTH, // min + MAX_DEPTH); // max + depth->set_precision(3); + depth->initialize(); + y += height; + + + + rate = new PluginParam(plugin, + this, + x1, + x3, + x4, + y, + text_w, + 0, // output_i + &plugin->config.rate, // output_f + 0, // output_q + "Rate (Hz):", + MIN_RATE, // min + MAX_RATE); // max + rate->set_precision(3); + rate->initialize(); + y += height; + + char string[BCTEXTLEN]; + int y2 = y + BC_Pot::calculate_h() / 2; + add_subwindow(new BC_Title(x1, y2, _("Waveform:"))); + add_tool(waveform = new TremoloWaveForm(plugin, + x2, + y2, + waveform_to_text(string, plugin->config.waveform))); + waveform->create_objects(); + + show_window(); +} + +void TremoloWindow::update() +{ + offset->update(0, 0); + depth->update(0, 0); + rate->update(0, 0); + char string[BCTEXTLEN]; + waveform->set_text(waveform_to_text(string, plugin->config.waveform)); +} + + + +char* TremoloWindow::waveform_to_text(char *text, int waveform) +{ + switch(waveform) + { + case SINE: sprintf(text, _("Sine")); break; + case SAWTOOTH: sprintf(text, _("Sawtooth")); break; + case SAWTOOTH2: sprintf(text, _("Rev Sawtooth")); break; + case SQUARE: sprintf(text, _("Square")); break; + case TRIANGLE: sprintf(text, _("Triangle")); break; + } + return text; +} + + +void TremoloWindow::param_updated() +{ +} + + + + + +TremoloWaveForm::TremoloWaveForm(Tremolo *plugin, int x, int y, char *text) + : BC_PopupMenu(x, y, xS(120), text) +{ + this->plugin = plugin; +} + + +TremoloWaveForm::~TremoloWaveForm() +{ +} + + +void TremoloWaveForm::create_objects() +{ + char string[BCTEXTLEN]; + add_item(new TremoloWaveFormItem(plugin, + TremoloWindow::waveform_to_text(string, SINE), + SINE)); + add_item(new TremoloWaveFormItem(plugin, + TremoloWindow::waveform_to_text(string, SAWTOOTH), + SAWTOOTH)); + add_item(new TremoloWaveFormItem(plugin, + TremoloWindow::waveform_to_text(string, SAWTOOTH2), + SAWTOOTH2)); + add_item(new TremoloWaveFormItem(plugin, + TremoloWindow::waveform_to_text(string, SQUARE), + SQUARE)); + add_item(new TremoloWaveFormItem(plugin, + TremoloWindow::waveform_to_text(string, TRIANGLE), + TRIANGLE)); +} + + + +TremoloWaveFormItem::TremoloWaveFormItem(Tremolo *plugin, char *text, int value) + : BC_MenuItem(text) +{ + this->plugin = plugin; + this->value = value; +} + +TremoloWaveFormItem::~TremoloWaveFormItem() +{ +} + +int TremoloWaveFormItem::handle_event() +{ + plugin->config.waveform = value; + get_popup_menu()->set_text(get_text()); + plugin->send_configure_change(); + return 1; +} diff --git a/cinelerra-5.1/plugins/tremolo/tremolo.h b/cinelerra-5.1/plugins/tremolo/tremolo.h new file mode 100644 index 00000000..404c8e4e --- /dev/null +++ b/cinelerra-5.1/plugins/tremolo/tremolo.h @@ -0,0 +1,148 @@ + +/* + * CINELERRA + * Copyright (C) 2008-2019 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef TREMOLO_H +#define TREMOLO_H + +class Tremolo; + +#include "pluginaclient.h" + + +#define SINE 0 +#define SAWTOOTH 1 +#define SAWTOOTH2 2 +#define SQUARE 3 +#define TRIANGLE 4 +#define TOTAL_WAVEFORMS 5 + +class TremoloConfig +{ +public: + TremoloConfig(); + + + int equivalent(TremoloConfig &that); + void copy_from(TremoloConfig &that); + void interpolate(TremoloConfig &prev, + TremoloConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame); + void boundaries(); + + +// starting phase offset in ms + float offset; +// how much the phase oscillates in ms + float depth; +// rate of phase oscillation in Hz + float rate; + int waveform; +}; + + + + +class Tremolo : public PluginAClient +{ +public: + Tremolo(PluginServer *server); + ~Tremolo(); + + void update_gui(); + + + +// required for all realtime/multichannel plugins + PLUGIN_CLASS_MEMBERS(TremoloConfig); + int process_buffer(int64_t size, + Samples *buffer, + int64_t start_position, + int sample_rate); + void reallocate_dsp(int new_dsp_allocated); + void reallocate_history(int new_allocation); + + int is_realtime(); + int is_synthesis(); + int is_multichannel(); + void save_data(KeyFrame *keyframe); + void read_data(KeyFrame *keyframe); + + int table_size; + double *table; + int table_offset; +// detect seeking + int64_t last_position; + int need_reconfigure; +}; + + + +class TremoloWaveForm; +class TremoloWindow : public PluginClientWindow +{ +public: + TremoloWindow(Tremolo *plugin); + ~TremoloWindow(); + + void create_objects(); + void update(); + static char* waveform_to_text(char *text, int waveform); + void param_updated(); + + Tremolo *plugin; + PluginParam *offset; + PluginParam *depth; + PluginParam *rate; + TremoloWaveForm *waveform; +}; + + +class TremoloWaveForm : public BC_PopupMenu +{ +public: + TremoloWaveForm(Tremolo *plugin, int x, int y, char *text); + ~TremoloWaveForm(); + + void create_objects(); + Tremolo *plugin; +}; + +class TremoloWaveFormItem : public BC_MenuItem +{ +public: + TremoloWaveFormItem(Tremolo *plugin, char *text, int value); + ~TremoloWaveFormItem(); + + int handle_event(); + + int value; + Tremolo *plugin; +}; + + + + +#endif + + +