// v3.5 // // wvwwvwvww // \ / // \______/ // // Joe's Filters // for Final Cut Pro // (C) 2002 Joe Maller // http://www.joesfilters.com // http://www.fxscriptreference.org filter "Joe's Time Bender"; group "Joe's Video & Time Filters"; input nowFrame, "Frame", slider, 0, 0, 100; input frameBlender, "Frame Blending", checkbox, 1; input reversefields, "Reverse Fields", checkbox, 0; input valuecheck, "Show Timecode", checkbox, 0; input formatting, "Timecode Format", popup, 1, "Clip Default", "24 fps", "25 fps (PAL)", "30 fps (Drop Frame NTSC)", "30 fps (No Drop Frame)", "60 fps (Drop Frame)", "60 fps", "16mm Film", "35mm Film"; //, "integer", "kfloat2", "kFloat4", "kFloat6"; input instructions, "Instructions", Text, "Set multiple keyframes to remap time. The first frame of the clip is 0, the last frame is 100. Bending the curve changes time." TextHeight 4 input title, "Joe's Filters", Label,""; input title1, "www.joesfilters.com", Label,""; producesAlpha; code //numreporter subroutine On numReporter(value reporterData, string reporterstring, value subformat, value height) string reporter; color fontcolor; fontcolor = {200,255,255,255}; settextfont("Verdana"); setTextstyle(kbold); setTextjustify(kcenterjustify); setTextSize(30 * zoomfactor); ChannelFill(xbuffer, 0, 0, 0, 0) NumToString(reporterData, reporter, subformat); reporter = reporterstring + " " + reporter DrawString(reporter, 0, height, 1.2, dest, fontcolor , aspectof(dest)) End //end numreporter // used to scale type in numreporter float zoomfactor, x, y; dimensionsOf(Dest, x, y); zoomfactor = x/720; float sourceDuration, sourceOffset, i, j, aspect, fieldswitch, FieldPicker, blendopacity; point framebox[4], fieldbox[4]; aspect = aspectOf(dest); fieldswitch = integer(aspect + 0.5); // results in 1 or 2, should use fieldprocessing in future versions boundsof(dest, fieldbox); image xbuffer[(fieldbox[1].x - fieldbox[0].x)][(fieldbox[2].y - fieldbox[0].y)]; image clipbuffer[(fieldbox[1].x - fieldbox[0].x)][(fieldbox[2].y - fieldbox[0].y) * fieldswitch]; boundsof(clipbuffer, framebox); getLimits(clip1, sourceDuration, sourceOffset); nowFrame = nowFrame/100 * duration/fieldswitch; FieldPicker = (nowFrame - integer(nowFrame) < 0.5) ? 1 : 0; if reversefields FieldPicker = -FieldPicker +1; end if getvideo(clip1, -sourceOffset + integer(nowFrame), clipbuffer); if fieldswitch == 2 j = fieldbox[0].y; for i = framebox[0].y to framebox[2].y step 2; framebox[0].y = i + FieldPicker; framebox[1].y = i + FieldPicker; framebox[2].y = i + 1 + FieldPicker; framebox[3].y = i + 1 + FieldPicker; fieldbox[0].y = j; // j starts at the topmost row of pixels in outfield and counts up fieldbox[1].y = j; fieldbox[2].y = j + 1; fieldbox[3].y = j + 1; j++ // increases the target row, used to build a half-height image. BlitRect(clipbuffer, framebox, dest, fieldbox); // copy the contents of the selected field next; else dest = clipbuffer; end if if frameBlender == 1; FieldPicker = -FieldPicker +1; // all three of the following use the reversed field if (nowFrame - integer(nowFrame) < 0.25) // get previous field 2 getvideo(clip1, -sourceOffset + integer(nowFrame) - 1, clipbuffer); blendopacity = (nowFrame - integer(nowFrame)) * 2 + 0.5; else if (nowFrame - integer(nowFrame) >= 0.25) && (nowFrame - integer(nowFrame) < 0.75) //blend fields from single, selected frame //clip is already in clipframe, switch fields blendopacity = (nowFrame - integer(nowFrame) - 0.25) * 2; else if (nowFrame - integer(nowFrame) >= 0.75) // get next field 1 getvideo(clip1, -sourceOffset + integer(nowFrame) + 1, clipbuffer); blendopacity = (nowFrame - integer(nowFrame) - 0.25) * 2 -1; end if if blendopacity > 0.5 blendopacity = 1 - blendopacity; end if if fieldswitch == 2 boundsof(dest, fieldbox); boundsof(clipbuffer, framebox); j = fieldbox[0].y; for i = framebox[0].y to framebox[2].y step 2; framebox[0].y = i + FieldPicker; framebox[1].y = i + FieldPicker; framebox[2].y = i + 1 + FieldPicker; framebox[3].y = i + 1 + FieldPicker; fieldbox[0].y = j; // j starts at the topmost row of pixels in outfield and counts up fieldbox[1].y = j; fieldbox[2].y = j + 1; fieldbox[3].y = j + 1; j++ // increases the target row, used to build a half-height image. BlitRect(clipbuffer, framebox, xbuffer, fieldbox); // copy the contents of the selected field next; else xbuffer = clipbuffer; end if matte(xbuffer, dest, dest, blendopacity, kalpha); end if; float w, h; dimensionsOf(dest, w, h); if (valuecheck) float framerate, df; GetTimecode(clip1, j, framerate, df) if formatting == 1; // 'clip default' and set formatting based on clip if (df == 1) // is either 30 or 60fps if (framerate > 30) formatting = k60df else formatting = k30df end if else if (framerate == 24) formatting = k24fps; else if (framerate == 25) formatting = k25fps; else if (framerate == 30) formatting = k30fps; else if (framerate == 60) formatting = k60fps; else if (framerate == 16) formatting = k16mm; else if (framerate == 35) formatting = k35mm; end if else if (formatting == 2); formatting = k24fps; else if (formatting == 3); formatting = k25fps; else if (formatting == 4); formatting = k30df; else if (formatting == 5); formatting = k30fps; else if (formatting == 6); formatting = k60df; else if (formatting == 7); formatting = k60fps; else if (formatting == 8); formatting = k16mm; else if (formatting == 9); formatting = k35mm; else if (formatting == 10); formatting = kinteger; else if (formatting == 11); formatting = kFloat2; else if (formatting == 12); formatting = kFloat4; else if (formatting == 13); formatting = kFloat6; end if j += sourceOffset + integer(nowFrame - 0.5); // corrects for timecode values rounding up instead of towards zero numReporter(j, "Source Timecode:", formatting, h/2*0.75) end if