With Support from Apple
(Page 2 of 3 pages for this article < 1 2 3 >)
Monday, March 16, 2009
FXScript: FCP’s Most Under-appreciated Feature
Adam Wilt | 03/16
I whip up a dead-pixel masker for a feature, and you get the filter for free, along with a quick tour of FXScript.
A Whirlwind Tour of FXBuilder
“OK”, you say, “I’m convinced. How do I make cool filters at home in my spare time, garnering the respect of my peers and the amorous attentions of my object of desire?”
Well, I can show you how to make cool filters at home in your spare time. The rest is up to you.
You can launch FXBuilder from FCP’s Tools menu, but that opens a blank editor window, as blank as your mind when you see the blank window blankly staring back at you. It’s easier and less intimidating to open an existing filter, transition, or generator in an editor; that way you have both a template to start building on, and an example of how it’s done. Indeed, one of the best ways to learn FXScript is to just open up any interesting-looking effects in editors and see how they’re written.
Select the Effects tab in the Browser and control-click on an effect for its context menu.
Select “Open in Editor”. Bam! Its secrets are laid open before your eyes!
(Mind you, this doesn’t work with every effect. Those with the Effect Class of “FxPlug” aren’t FXScripts and aren’t editable, and some 3rd-party FXScript effects are encoded to keep prying eyes out.)
When you have an editor open, a new FXBuilder menu appears in the menu bar:
The FXBuilder menu, with keying functions highlighted.
(If you don’t see the menu on your system, make sure the FXBuilder window is active.)
The menu lets you run the script in test mode, stop it, export the script as a text file, or save it as a plugin or an encoded (read-only) plugin. It also lists all the data types, functions, etc. that FXBuilder knows about: you can scroll through, for example, to Functions > Key > RGBColorKey, and if you click on it, FXBuilder inserts the following into your code:
RGBColorKey(srcImage, destImage, redTarget, redPass, greenTarget, greenPass, blueTarget, bluePass, softness, fillRGB)
If you look up RGBColorKey in “Using FXScript”, it says:
Fills either the alpha or RGB channels of the destination image buffer with a mask created by comparing the values of the pixels in the source image to the “pass” values and “target” numbers specified. “Softness” specifies the softness of the mask. “FillRGB” specifies whether the alpha or RGB channels are filled with the results.
Joe Maller’s FXScript Reference site doesn’t list any user comments for RGBColorKey; it only lists the parameters and says, “Related Links: BGDiff”.
That means that nobody’s seen the need to further explain the function or describe its parameters—which means it’s up to you to figure it out. You’ll observe that the parameter listing doesn’t say anything about what kind of parameters these are: Image buffers? Regions? Rectangles? Integers between 0-255? Floating-point numbers from 0.0-1.0? If you can’t figure it out from context, or by looking at other FXScripts, you just have to try something and see if it works.
Sometimes, folks have seen the need to add commentary. For the Point input control, “Using FXScript” simply says
input varName, “UIName”, Point, x, y
Creates a point entry control.
while the FXScript Reference says, at http://www.fxscriptreference.org/inputcontrols/point
Additional Notes
the point input control yields confusing values.
by stib on 13 Jun, 2004 08:36, Applies to: FCP 4.5 (HD) from: 203.164.168.184
don’t expect the point control to return pixel values, instead it returns the proportion of the frame from the centre. So a selecting point at the top right edge of frame yields {-0.5, 0.5}. Even though the user sees pixel values in the control box.
It’s quite clever really, but a bit confusing.
This is an especially useful clue since the numerical readouts in the Point input control (as used in the “Location” control of Pixel Mask) do show you the pixel values!
Really, that’s the hardest part about working with FXScript: the lack of info on the types and allowable ranges of all the various parameters. It’s a bit of a treasure hunt to find the information, but if you don’t mind the occasional treasure hunt and some trial-and-error experimentation, you can get a lot of cool things done relatively painlessly.
The FXBuilder window has two tabs: the FXBuilder Text Entry tab in which you edit your script, and the FXBuilder Input Controls. The Input Controls tab has two source wells into which you can drop one or two clips, generators, or stills to use as test sources. When you run your script, your scripts controls also appear in the tab, and a small, 320x240 test window appears, showing the first frame of your source(s) as processed by your script, and letting you play with the controls.
The Input Controls tab, and the test window.
For a lot of my Pixel Mask testing, where I wanted to see exactly what the edges of my mask were doing, I used the Two Color Ray (Video Generators > Render > Two Color Ray) as shown; other times I used a circular gradient, or bits of random clips (the actual clips I wanted to work with, when scaled down to 320x240, had their dead pixels shrunk down to invisibility, so they weren’t useful in test mode).
If you make a syntax error, FXBuilder will tell you when you try to run the script by highlighting the error in the Text Entry tab and giving you an appropriate error message. For example, if I have the code
point srcPoly[4], destPoly[4]
boundsOf(Src1, srcPoly)
boundsOf(Dest, point) // mistake: “point” should be “destPoly”
and I try to run the script it’s in, FXBuilder highlights the word “point” in the last line, and gives me a popup saying, “Error in FXBuilder script: FXScript Error: Type mismatch”. It’s then up to me to figure out what my “type mismatch” is, and fix it.
Once you’ve made your script do what you want, you have three choices:
- Create Plugin: make an FCP plugin that anyone can open, read, and edit.
- Create Encoded Plugin: make an FCP plugin that can’t be opened in FXBuilder.
- Export Text: make a plain-text file that anyone can open, read, and edit, and it still works as a plugin.
I tend to save things as text, so I can edit them in Text Edit or XCode as well as in FCP. if you’re selling your plugin, you may want to save it as an encoded plugin, but be sure to save an un-encoded version or a plain-text version as well, otherwise you won’t be able to edit it again! (Note: the encoding isn’t a perfect copy-protection scheme, either, so don’t depend on it to keep your secrets safe from determined safe-crackers.)
To use your plugin for real work, quit FCP, and drop the plugin in /Library/Application Support/Final Cut Pro System Support/Plugins (it’s common practice to put your plugins in their own folder inside the Plugins folder). Restart FCP, and your plugin should appear in Effects. Alas, you can’t just save the file into the Plugins folder while FCP is running and keep going; FCP won’t pick up the changes to the plugins until you restart it.
Next: Pixel Mask unmasked line-by-line, and where to get it…
(Page 2 of 3 pages for this article < 1 2 3 >)
Thanks, Andy. Y’know, I used to go to that site all the time, and had forgotten about it, and Joe’s big text box redirecting folks to the new, “improved” site threw me off the scent. Silly me! I’ll update the article; thanks again!
Posted by Adam Wilt on 03/16 at 11:55 PM
Thank you for the informative examples.
I have looked all over for information on what should be a very simple task, and cannot seem to find any. How do you combine two fxScript effects into a single script?
The problem seems to be that the first script starts with src1 and spits results into dest, but then the second one is trying to do the same thing. I have not found a way of copying src1, src2, or dest into another variable. I thought the “image” variable type should work, but how?
Posted by .(JavaScript must be enabled to view this email address) on 08/31 at 02:37 AM
as you’ve guessed you can just create and use an image buffer (with the same dimensions of your src/dest) and use it to store the result of the first script (instead of dest) and to feed the second script (instead of src)
eg you could set up a buffer “buf” as below
dimensionsof(dest, framesize.h, framesize.v);
image buf[framesize.h][framesize.v];
then use it directly in place of “dest” or “src1” etc as needed, or simply use it to hold such info using a simple x=y type instruction
eg buf = dest;
hope it helps
Andy
Posted by Andy on 08/31 at 04:40 AM
oops ... forgot to include the definition of the “framesize” variable too
dimensionsof(dest, framesize.h, framesize.v);
image buf[framesize.h][framesize.v];
should read:
point framesize;
dimensionsof(dest, framesize.h, framesize.v);
image buf[framesize.h][framesize.v];
Posted by Andy on 08/31 at 04:52 AM
Thank you, Andy, for such a prompt response! I will try it out tomorrow.
Posted by .(JavaScript must be enabled to view this email address) on 08/31 at 05:56 AM
It works! But it took me some time with other issues, like duplicate variable names from combining the effects, before I actually saw it work. I have now managed to combine three effects on one video clip, duplicate the clip into another variable, and add two more effects, with the end result being a single reflected image effect.
I still haven’t figured out how to assign a value to a point variable in my code (such as the center point). As everyone says, the documentation is rather skimpy, and it seems to tell us only how to define a point variable, but not how to give it a value.
Anyhow, I’ll keep learning. Thanks for the help!
Posted by .(JavaScript must be enabled to view this email address) on 09/01 at 07:28 PM
here you go, example code for defining and assigning a value to a point variable:
point p;
p = {0, 0};
Posted by Andy on 09/01 at 07:41 PM
Again, thank you! I had tried p = [0, 0]; and p = (0, 0); but neither of them worked. Knowing the syntax makes all the difference! And the error message I got was that there was a missing parenthesis at the comma position! (But of course, for an x,y coordinate point, p = (0); just wouldn’t make much sense.) Thank you!
BTW, are there any forums for fxScript that would be more appropriate for asking questions like these? maybe a place where I could also post my code? (Someone might appreciate it, and if they don’t, they might improve it for me.
Posted by .(JavaScript must be enabled to view this email address) on 09/01 at 09:54 PM
> are there any forums for fxScript
None that I know of, but you can always use Apple’s own Final Cut Pro discussions forum to get your questions/code out there.
http://discussions.apple.com/forum.jspa?forumID=939
If you’re serious about this stuff then you should join Apple’s pro-app-dev mailing list
http://lists.apple.com/mailman/listinfo/pro-apps-dev
Posted by Andy on 09/01 at 10:49 PM
I’ve been learning a lot about fxScript. One of the more frustrating pieces of knowledge is just how little documentation on it there is. Many functions are only partly documented, and a few, seemingly not at all.
I am working with CJK characters, and need a way of applying an fxScript that will automatically exchange every occurrence of an ancient form of the comma with a modern equivalent. I would also like to be able to parse the text for word splits. (I’m making a text wrap function which will automatically insert return characters to fit a user-adjustable line width.)
Do you know of any way to catch CJK characters (double byte) and to insert them back into the text?
Posted by .(JavaScript must be enabled to view this email address) on 10/15 at 03:21 AM
The “Using FXScript” PDF implies that most of the String and Text functions are double-byte compatible (pages 47-48). If they actually work, you may be able to use FindString to look for both the archaic comma form and for whitespace (word break) characters; CharsOf to break the text into smaller substrings; and MeasureString to check widths for line wraps. Then it’s just the tedious process of marching through your source string(s), breaking them into words, replacing the commas, and reassembling them them with newlines inserted at the appropriate places.
If that doesn’t work out, you may have better luck pre-processing your text with AppleScript (or even a small Cocoa program), and pasting the result back into FCP’s text generators, though you’ll have to work out the correspondence between text metrics in AppleScript and the text metrics in FCP.
Posted by Adam Wilt on 10/15 at 09:49 AM
|