BatchRenderGUI script updates

johnmeyer wrote on 11/23/2003, 7:29 PM
I have seen several changes and updates to the original batch render GUI script. Below is my version. It is quite similar to the original, with the following enhancements:

1. It now correctly selects whether to render the project, the selection, or the region. The original version seldom made the correct decision, and I often ended up rendering the wrong thing.

2. I fixed several bugs relating to how other defaults are selected.

3. The script now puts the actual region names into the rendered file names, rather than using just an index number.

4. I kept the index number for region names, but now I add this number before the region name, padded with initial zeros, so it can be used to sort the resulting regions.

None of this is earth-shattering, but it seems to make the script work better.

I'm posting the script below using the HTML codes needed to preserve the formatting. Unfortunately, these codes also cause the carriage returns to be replaced with line breaks. Some people have problems copying and pasting the results and getting them to work (hint: you can search/replace the line breaks and change them to carriage returns). If anyone has a better way to post these scripts so people don't have this problem, but they can still be easily read, please let me know.


/**
* Sample script that performs batch renders with GUI for selecting
* render templates.
*
* Creation Date: Mar. 25, 2003.
* Reivsed by JHM November 23, 2003

**/
import System;
import System.Collections;
import System.Text;
import System.IO;
import System.Drawing;
import System.Windows.Forms;
import SonicFoundry.Vegas;

// set this to true if you want to allow files to be overwritten
var overwriteExistingFiles = true;

try {

// here are some default variables for the GUI.
var defaultBasePath : String = Vegas.Project.FilePath;
if ((null == defaultBasePath) || (0 == defaultBasePath.length)) {
defaultBasePath = "E:\JHM_";
} else {
var dir = Path.GetDirectoryName(defaultBasePath);
var fileName = Path.GetFileNameWithoutExtension(defaultBasePath);
defaultBasePath = dir + Path.DirectorySeparatorChar + fileName + "_";
}

var dlog = new BatchRenderDialog();
if (DialogResult.OK == dlog.ShowDialog()) {
var selectedTemplates = dlog.GetCheckedTemplates();
// inform the user of some special failure cases
if (0 == selectedTemplates.Count)
throw "no render templates selected";
var outputFilePath = dlog.fileNameBox.Text;
var renderMode = RenderMode.Project;
if (dlog.renderRegions.Checked) {
renderMode = RenderMode.Regions;
} else if (dlog.renderSelection.Checked) {
renderMode = RenderMode.Selection;
}
var renderSelection = dlog.renderSelection.Checked;
DoBatchRender(selectedTemplates, outputFilePath, renderMode);
}
} catch (e) {
if (!e.skipMessageBox)
MessageBox.Show(e);
}

enum RenderMode {
Project = 0,
Selection,
Regions,
}

function DoBatchRender(selectedTemplates : ArrayList,
basePath : String,
renderMode : RenderMode)
{
var outputDirectory = Path.GetDirectoryName(basePath);
var baseFileName = Path.GetFileName(basePath);

// make sure the output directory exists
if (!Directory.Exists(outputDirectory))
{
var msg = new StringBuilder("The output directory (");
msg.Append(outputDirectory);
msg.Append(") does not exist.\n");
msg.Append("Please specify directory and base file name using the Browse button.");
throw msg;
}

var zero : int = 0;
var zeroTime = new Timecode();
var renderStart, renderLength;

var templateFound = false;

// enumerate through each selected render template
var selections = new Enumerator(selectedTemplates);
while (!selections.atEnd()) {
var tag = selections.item();
var renderer = tag.renderer;
var renderTemplate = tag.template;

// construct the file name (most of it)
var filename = new StringBuilder(outputDirectory);
filename.Append(Path.DirectorySeparatorChar);
filename.Append(FixFileName(baseFileName));

if (renderMode == RenderMode.Regions) {
var regions = new Enumerator(Vegas.Project.Regions);
var regionIndex = zero;
while (!regions.atEnd()) {
var region = regions.item();
var regionFilename = new StringBuilder(filename);

// Pad index number with leading zeros
regionIndex = ( regionIndex < 10 ) ? "0" + regionIndex : regionIndex;
regionFilename.Append(regionIndex);
regionFilename.Append("_");
regionFilename.Append(region.Label);

// need to strip off the extension's leading "*"
regionFilename.Append(renderer.FileExtension.substring(1));

// Render the region
renderStart = region.Position;
renderLength = region.Length
DoRender(regionFilename.ToString(), renderer, renderTemplate, renderStart, renderLength);
regionIndex++;
regions.moveNext();
}
} else {
// need to strip off the extension's leading "*"
filename.Append(renderer.FileExtension.substring(1));

if (renderMode == RenderMode.Selection) {
renderStart = Vegas.SelectionStart;
renderLength = Vegas.SelectionLength;
} else {
renderStart = new Timecode();
renderLength = Vegas.Project.Length;
}

DoRender(filename.ToString(), renderer, renderTemplate, renderStart, renderLength);
}
selections.moveNext();
}
}

/**
* Perform the render. The Render method returns a member of the
* RenderStatus enumeration. If it is anything other than OK, exit
* the loops. This will throw an error message string if the render
* does not complete successfully.
**/

function DoRender(fileName, rndr, rndrTemplate, start, length) {
ValidateFileName(fileName);

// make sure the file does not already exist
if (!overwriteExistingFiles && File.Exists(fileName)) {
throw "File already exists: " + fileName;
}

// perform the render. The Render method returns
// a member of the RenderStatus enumeration. If
// it is anything other than OK, exit the loops.

var status = Vegas.Render(fileName, rndrTemplate, start, length);

// if the render completed successfully, just return
if (status == RenderStatus.Complete)
return;

// if the user canceled, throw out a special message that won't be
// displayed.
if (status == RenderStatus.Canceled) {
var cancelMsg = new String("User canceled");
cancelMsg.skipMessageBox = true;
throw cancelMsg;
}

// if the render failed, throw out a detailed error message.
var msg : StringBuilder = new StringBuilder("Render failed:\n");
msg.Append("\n file name: ");
msg.Append(fileName);
msg.Append("\n Renderer: ");
msg.Append(rndr.FileTypeName);
msg.Append("\n Template: ");
msg.Append(rndrTemplate.Name);
msg.Append("\n Start Time: ");
msg.Append(start.ToString());
msg.Append("\n Length: ");
msg.Append(length.ToString());
throw msg;
}

function FixFileName(name : System.String) : System.String
{
var replacementChar : System.Char = '-';
var colon : System.Char = ':';
name = name.Replace(Path.DirectorySeparatorChar, replacementChar);
name = name.Replace(colon, replacementChar);
var illegalCharCount = Path.InvalidPathChars.Length;
var i = 0;
while (i < illegalCharCount) {
name = name.Replace(Path.InvalidPathChars[i], replacementChar);
i++;
}
return name;
}

function ValidateFileName(fileName : System.String) {
if (fileName.length > 260)
throw "file name too long: " + fileName;
var illegalCharCount = Path.InvalidPathChars.Length;
var i = 0;
while (i < illegalCharCount) {
if (0 <= fileName.IndexOf(Path.InvalidPathChars[i])) {
throw "invalid file name: " + fileName;
}
i++;
}
}

class BatchRenderDialog extends Form {
var browseButton : BrowseButton;
var fileNameBox : TextBox;
var templateTree : TemplateTreeView;
var renderProject : RadioButton;
var renderRegions : RadioButton;
var renderSelection : RadioButton;

function BatchRenderDialog() {
this.Text = "Batch Render";
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.StartPosition = FormStartPosition.CenterScreen;
this.Width = 600;

var titleBarHeight = this.Height - this.ClientSize.Height;
var buttonWidth = 80;

fileNameBox = addTextControl("Base File Name", titleBarHeight + 6, 460, 10, defaultBasePath);

browseButton = new BrowseButton(fileNameBox);
browseButton.Left = fileNameBox.Right + 4;
browseButton.Top = fileNameBox.Top - 2;
browseButton.Width = buttonWidth;
browseButton.Height = browseButton.Font.Height + 12;
browseButton.Text = "Browse...";
Controls.Add(browseButton);

templateTree = new TemplateTreeView();
templateTree.Left = 10;
templateTree.Width = this.Width - 20;
templateTree.Top = browseButton.Bottom + 10;
templateTree.Height = 300;
templateTree.CheckBoxes = true;
Controls.Add(templateTree);
FillTemplateTree();

var buttonTop = templateTree.Bottom + 16;
var buttonsLeft = this.Width - (2*(buttonWidth+10));

renderProject = addRadioControl("Render Project", 6, buttonTop);
renderSelection = addRadioControl("Render Selection", renderProject.Right, buttonTop);
renderRegions = addRadioControl("Render Regions", renderSelection.Right, buttonTop);

// New code added here to correctly identify whether to render selection, project, or region
var dSelStart = Vegas.SelectionStart.ToMilliseconds();
var dSelEnd = Vegas.SelectionStart.ToMilliseconds() + Vegas.SelectionLength.ToMilliseconds();
var dCursor = Vegas.Cursor.ToMilliseconds();

if (dSelStart == dCursor || dSelEnd == dCursor) {
renderSelection.Checked = true;
} else {
renderProject.Checked = true;
}

var okButton = new Button();
okButton.Text = "OK";
okButton.Left = this.Width - (2*(buttonWidth+10));
okButton.Top = buttonTop;
okButton.Width = buttonWidth;
okButton.Height = okButton.Font.Height + 12;
okButton.DialogResult = System.Windows.Forms.DialogResult.OK;
AcceptButton = okButton;
Controls.Add(okButton);

var cancelButton = new Button();
cancelButton.Text = "Cancel";
cancelButton.Left = this.Width - (1*(buttonWidth+10));
cancelButton.Top = buttonTop;
cancelButton.Height = cancelButton.Font.Height + 12;
cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
CancelButton = cancelButton;
Controls.Add(cancelButton);

this.Height = titleBarHeight + okButton.Bottom + 8;

}

function addTextControl(labelName, left, width, top, defaultValue) {
var label = new Label();
label.AutoSize = true;
label.Text = labelName + ":";
label.Left = left;
label.Top = top + 4;
Controls.Add(label);

var textbox = new TextBox();
textbox.Multiline = false;
textbox.Left = label.Right;
textbox.Top = top;
textbox.Width = width - (label.Width);
textbox.Text = defaultValue;
Controls.Add(textbox);

return textbox;
}

function addRadioControl(labelName, left, top) {
var label = new Label();
label.AutoSize = true;
label.Text = labelName;
label.Left = left;
label.Top = top + 4;
Controls.Add(label);

var radiobutton = new RadioButton();
radiobutton.Left = label.Right;
radiobutton.Width = 36;
radiobutton.Top = top;
Controls.Add(radiobutton);

return radiobutton;
}

function FillTemplateTree() {
var renderers = new Enumerator(Vegas.Renderers);
while (!renderers.atEnd()) {
var renderer = renderers.item();
var rendererNode = new TreeNode(renderer.FileTypeName);
rendererNode.Tag = renderer;
templateTree.Nodes.Add(rendererNode);
var templates = new Enumerator(renderer.Templates);
while (!templates.atEnd()) {
var template = templates.item();
var templateNode = new TreeNode(template.Name);
var tag = new Object();
tag.renderer = renderer;
tag.template = template;
templateNode.Tag = tag;
rendererNode.Nodes.Add(templateNode);
templates.moveNext();
}
renderers.moveNext();
}
}

function GetCheckedTemplates() {
var checkedTemplates = new ArrayList();
var rendererNodes = new Enumerator(templateTree.Nodes);
while (!rendererNodes.atEnd()) {
var rendererNode = rendererNodes.item();
GetCheckedTemplatesHelper(checkedTemplates, new Enumerator(rendererNode.Nodes));
rendererNodes.moveNext();
}
return checkedTemplates;
}

function GetCheckedTemplatesHelper(checkedTemplates, templateNodes) {
if (templateNodes.atEnd()) return;
var templateNode = templateNodes.item();

if (templateNode.Checked) {
checkedTemplates.Add(templateNode.Tag);
}
templateNodes.moveNext();
GetCheckedTemplatesHelper(checkedTemplates, templateNodes);
}
}

// Button subclass that shows a save file dialog when clicked
class BrowseButton extends Button {
var myResultBox = null;

function BrowseButton(resultBox) {
myResultBox = resultBox;
}

protected override function OnClick(e : EventArgs) {
var saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "All Files (*.*)|*.*";
saveFileDialog.CheckPathExists = true;
saveFileDialog.AddExtension = false;
if (null != myResultBox) {
var filename = myResultBox.Text;
var initialDir = Path.GetDirectoryName(filename);
if (Directory.Exists(initialDir)) {
saveFileDialog.InitialDirectory = initialDir;
}
saveFileDialog.DefaultExt = Path.GetExtension(filename);
saveFileDialog.FileName = Path.GetFileNameWithoutExtension(filename);
}
if (System.Windows.Forms.DialogResult.OK == saveFileDialog.ShowDialog()) {
if (null != myResultBox) {
myResultBox.Text = Path.GetFullPath(saveFileDialog.FileName);
}
}
}
}

class TemplateTreeView extends TreeView {

protected function OnAfterCheck(e : TreeViewEventArgs) {
super.OnAfterCheck(e);
if (e.Node.Checked) {
if (0 != e.Node.Nodes.Count) {
if ((e.Action == TreeViewAction.ByKeyboard) || (e.Action == TreeViewAction.ByMouse)) {
SetChildrenChecked(new Enumerator(e.Node.Nodes), true);
}
} else if (!e.Node.Parent.Checked) {
e.Node.Parent.Checked = true;
}
} else {
if (0 != e.Node.Nodes.Count) {
if ((e.Action == TreeViewAction.ByKeyboard) || (e.Action == TreeViewAction.ByMouse)) {
SetChildrenChecked(new Enumerator(e.Node.Nodes), false);
}
} else if (e.Node.Parent.Checked) {
if (!AnyChildrenChecked(new Enumerator(e.Node.Parent.Nodes))) {
e.Node.Parent.Checked = false;
}
}
}
}

protected function SetChildrenChecked(kidz, checked) {
if (kidz.atEnd()) return;
var kid = kidz.item();
if (kid.Checked != checked)
kid.Checked = checked;
kidz.moveNext();
SetChildrenChecked(kidz, checked);
}

protected function AnyChildrenChecked(kidz) : boolean {
if (kidz.atEnd()) return false;
var kid = kidz.item();
if (kid.Checked)
return true;
kidz.moveNext();
return AnyChildrenChecked(kidz);
}
}

Comments

PAW wrote on 11/25/2003, 12:42 PM

John I had a problem with the script rendering AC3 5.1 as AC3 Stereo

Did you ever experience this or have you tested it with this script?

Regards, Paul
cheroxy wrote on 11/27/2003, 8:43 AM
could you email me the js and I'll post it on my site. I have tried a few ways to cut and paste, but they don't work. The script is so nice that it is very long and would take forever to remove all the br's since my software won't let me replace it with anything but text.
thanks,
Carson
cbcalderwood at yahoo.com
ricklaut wrote on 11/27/2003, 2:40 PM
Can you post it at the Sundance site while you're at it? This sounds like one that would be very useful!

Rick
johnmeyer wrote on 11/28/2003, 5:59 PM
John I had a problem with the script rendering AC3 5.1 as AC3 Stereo

I saw your earlier posts, and was unable to test this because I haven't had the need to render in 5.1. However, I noted that Sony responded to one of your posts and indicated that this was a bug in Vegas itself, not in the script. If this is so, my script will probably exhibit the same behavior.

If the problem is indeed a bug in Vegas, I would guess that it has to do with how it reads the enumeration of script templates. This suggests a possible workaround. What I would suggest you do is this: Before running the script, Select File -> Render As, and choose Save As File Type: Dolby Digital AC-3, and then select for Template: 5.1 Surround DVD. Then, select the Custom button and immediately type a new name in the Template box at the top of the dialog. Use a name that doesn't begin in a number (just a hunch on my part). Something like "MySurroundTemplate." Click on the save icon. This will create a new template. Then, run the BatchGUI script. Your new template should now show up as a new item under "Dolby Digital AC-3." Select this item and see if it works (try it on a small project so you don't waste a lot of time.

Could you email me the js and I'll post it on my site. Carson
I sent the file to you via email.

Can you post it at the Sundance site while you're at it? This sounds like one that would be very useful! -- Rick

I could, but I have had a devil of a time getting my scripts to the person in charge. Can you give me an address or, if you don't want to post one here (if you do, spell out the @ so it doesn't get picked up by the spammers), at least point me to a link that has the address to use for upload.

John
PAW wrote on 11/30/2003, 2:07 AM

Good idea John.

Tried with a new template and it works ok. This was with the original gui script.

Sorry to be a pain but could you email me your update at tothewhites at yahoo.co.uk

Thanks, Paul
PAW wrote on 11/30/2003, 12:14 PM

Oops spoke too soon.

It worked the first time I created my own profile but after that the problem comes abck.

Regards, PAW
johnmeyer wrote on 11/30/2003, 12:35 PM
Interesting that it would work the first time, but not the second time. If you quit from Vegas, re-boot, and then run Vegas again, I wonder if it works the next time?

I've emailed the script to you, as you requested.

As I've stated in earlier emails, I wish Sony or someone would come up with a suggestion on how to better share scripts here. If I use the "pre" HTML code to format the script (in order to preserve formatting) -- which is what Sony suggested in this forum some months back -- everyone has problems when cutting/pasting because you get line breaks instead of carriage return/line feed at the end of each line. This is easy to fix in any word processor, but lots of people don't understand how to do this extra step, or don't want to take the time.

Any ideas on how we should post scripts in this forum so people can use them directly without this extra step, yet still retain the formatting?
ricklaut wrote on 11/30/2003, 6:31 PM
John -

You should be able to go to www.sundancemediagroup.com, register and post your script. Alternatively, send it to me at ricklautATlvcm.com and I should be able to put it up there for you.

Rick
johnmeyer wrote on 11/30/2003, 10:56 PM
Rick,

I'm registered at Sundance, but I'll send the file to you.

John