Community Forums Archive

Go Back

Subject:Newbie to Scripting: using Forge from CLI ?
Posted by: Angels
Date:5/11/2005 9:00:32 PM

I'm completely new to the concept of scripting, and I'm wondering if it can do what I need it to do. Essentially can Sound Forge be passed a command with arguments in DOS? Can, must, or does a script be set up to do this?

Suppose I wanted to call Forge from another program, asking it to resample a file to a specific frequency, giving it a path, filename, and destination sampling rate, high accuracy and anti-alias on. Do I have to create a script to do this, or can a script be used to do this?

I'll be getting a programmer to handle the scripting; if someone can confirm that this is possible and suggest the broad guidelines of what needs to be done, I'd appreciate it.

TIA

DSG

Subject:RE: Newbie to Scripting: using Forge from CLI ?
Reply by: jetdv
Date:5/12/2005 7:08:22 AM

You can call Sound Forge through DOS, specify that it run a script, and pass parameters to that script. Check out the scripting documentation for details.

Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: _TJ
Date:5/12/2005 7:11:40 PM

Yes, this is very doable. You can start Sound Forge with a command line that tells it to run a script, and you can pass that script arguments (including the name of a file to open, or the name a a file that has a list of files to open, or .. well, you get the idea.

Here's a sample batch file that will start Sound Forge and have it run a script.

------------------- snip here and save as ForgeRun.bat ------------

start "Forge" "c:\Program Files\Sony\Sound Forge 8.0\Forge80.exe" "/Script:d:\SoundForgeScripts\%1?file=%2"

-------------------- end of batch file --------------------

(note, in case the HTML comes out wierd, this should be a 1 line batch file.. You may have to change the path to the Forge80.exe and will almostly certainly have to change "d:\SoundForgeScripts" to match the location of the folder that you keep your scripts in.

This batch file takes 2 arguments, the first being the name of the script to run, and the second being the name of the file that you want that script to open, you can more arguments if you need to, although there is a limit on the amount of text you can put into a single command in a batch file.

To run this batch file (assuming that you called it ForgeRun.Bat) you would just type:

ForgeRun.bat MyScript.cs testfile.wav


This will launch Sound Forge (or find the currently running copy) and tell it to run the script called MyScript.cs and pass it the argument file=testfile.wav.

The script would look something like this

-------------------- snip here and save as MyScript.cs ---------

using System;
using System.IO;
using SoundForge;

public class EntryPoint {
public string Begin(IScriptableApp app) {

string filename = Script.Args.ValueOf("file");
if (null == filename || "" == filename)
return "This script requires you to specify a filename as an argument";

// this string will control what effects we apply before rendering
// MODIFY HERE to add other effects
string[] effects = new string[] {
"Resample|Resample to 22,050 Hz with anti-alias filter",
};

ISfFileHost file = app.OpenFile(filename, false, false);
if (file == null)
return "unable to open the file" + filename;

SfAudioSelection selectwholefile = new SfAudioSelection(0,-1);

SfStatus result = SfStatus.Success;
foreach (string effect in effects)
{
string[] str = effect.Split(new char[]{'|',';'},2);
string preset = null;
if (str.Length > 1)
preset = str[1];

file.DoEffect(str[0], preset, selectwholefile, EffectOptions.EffectOnly);
result = file.WaitForDoneOrCancel();
if (result != SfStatus.Success)
return "effect did not complete, quitting script";
}

file.SaveAs(file.Filename, file.SaveFormat.Guid, "Default Template", RenderOptions.OverwriteExisting | RenderOptions.RenderOnly);
file.WaitForDoneOrCancel();
file.Close(0);
return null;
}

public void FromSoundForge(IScriptableApp app)
{
ForgeApp = app; //execution begins here
app.SetStatusText(String.Format("Script '{0}' is running.", Script.Name));
string msg = Begin(app);
app.SetStatusText(msg != null ? msg : String.Format("Script '{0}' is done.", Script.Name));
}
public static IScriptableApp ForgeApp = null;
} //EntryPoint

-------------------- end script ---------------

So this will work, but it's a pretty heavyweight solution, you might be better of using a technique called 'watch folders' whereby a Sound Forge script runs all of the time, looking for files to show up in a given folder, and then operating on them when they do show up.

Or you may discover that you can do ALL of your programming in Sound Forge and not use batch files at all. Given the richness of the .NET runtime, A Sound Forge script can do pretty much anything you could do with a batch file.

tj



Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: Angels
Date:5/14/2005 7:37:10 AM

Wow! Thanks TJ for the incredibly verbose reply.

From what you've just described, the possibilities are truly staggering. Some of our code calls other programs with cli arguments for processing data, but I can see that there may be better ways of handling this.

I'm going to refer all this to the programmers I work with (who eat this stuff for lunch... ok, AFTER playing Quake...). I think it's going to be very useful.

Thanks, again.

Angels

Message last edited on5/14/2005 7:39:37 AM byAngels.
Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: Angels
Date:5/27/2005 1:57:58 PM


This script seems to be working except that I keep getting

"The file being rendered has exceeded the maximum size allowed for the selected format."

at the end of running it, and the file never gets saved so the script doesn't complete.

There's plenty of of room on disk, and the file is only 300k in size. It's 16-bit 44100 downsampled to 22050.

Thanks for any feedback.

A

Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: _TJ
Date:5/27/2005 8:22:55 PM

You can sometiimes get that error message if we can't find an appropriate renderer.

Show me the arguments that you are using for SaveAs() (or RenderAs()). Also, be sure you are using 8.0a, as there was a bug in 8.0 that would generate this error message if the sample rate of the file was changed and then you tried to Save() it from a script.

tj

Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: Angels
Date:5/30/2005 2:53:43 PM


Hi TJ,

We are running 8.0a. If a path is specified in the arguments and that is used in the "file.SaveAs" arguments, it's possible to save the file to another location, or to another name. Otherwise it baulks. This is working for now:

file.SaveAs(outfilename, file.SaveFormat.Guid, "Default Template", RenderOptions.RenderOnly | RenderOptions.OverwriteExisting );
file.WaitForDoneOrCancel();
file.Close(0);
return null;

where outfilename is an argument passed at the CLI.

There also seems to be a problem with "Default Template", which seems to be the last template used by Sound Forge, and not the original format as the docs specify.

To think a week ago C# was just a note.... I'll keep posting as I make more discoveries and breakthroughs.

Thanks

A

Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: Angels
Date:5/30/2005 5:35:35 PM


This is what was used to retrieve the original sample rate and enter it in the SaveAs options (instead of "Default Template"):

string file_sample_rate = String.Format("{0}",file.SampleRate);

file_sample_rate is entered as the SaveAs vTemplateNameOrData parameter.

A

Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: Angels
Date:5/31/2005 4:38:59 AM

OK, I think an explanation is in order for my last two posts, sorry!:

Because of my limited knowledge, I couldn't get one script to do everything. I've yet to really work out conditional arguments and variable assignments in C#... So one of my scripts resamples mono files, another extracts the right or left channel from a stereo file depending on a "r" or "l" argument and resamples it, and a third script simply extracts left or right from a stereo file without resampling.

The last two posts referred to the third script where I needed to know the original sampling rate in order to save to that sampling rate. As discussed, Forge would save to the last template used using "Default Template".

I just couldn't get everything done in one script in the time I had for this, but I will eventually get it done (lots of reading to do). Another thing I was wondering is how to pass parameters directly to the effects without using presets. It seems possible to do this: is it fully implemented? It would be much more flexible and fault tolerant to pass arguments to effects and render parameters without having to resort to presets at all.

Thanks to Sony for this really amazing flexibility.

A

Message last edited on5/31/2005 4:42:18 AM byAngels.
Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: _TJ
Date:5/31/2005 5:57:18 PM

"Default Template" will use the current settings of the file, but "Default Templte" or any other misspelling (or, in fact, ANY template name that doesn't exist) will use the last settings of the Save As dialog.


string file_sample_rate = String.Format("{0}",file.SampleRate);


Will give you a string containing "48000", or "44100" or whatever your rate is.
Then when you pass in "48000" as a template name, this will render using the last settings of the dialog unless you actually have a template named "48000".

incidently.


string file_sample_rate = file.SampleRate.ToString();

will give you the same result.

You should try using "Default Template" again, and if that really doesn't end up using the current file settings, then please post the full text of the script so that we can give it a try here. I suspect that you just had a misspelling rather than this being a bug.

Also, you might discover file.RenderAs() works better.

tj



Message last edited on5/31/2005 6:39:36 PM by_TJ.
Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: _TJ
Date:5/31/2005 5:58:15 PM

All effects can be driven directly using the ISfGenericPreset.Bytes property of the preset object. But in most cases, the structure of those bytes are not documented.

For some of the effects. We have also implemented the ISfGenericPreset.Fields for some of the built in effects, but this code is available only in Sound Forge 8.0a and above. Currently the following effects have direct preset parameter access.

Auto Trim/Crop, Bit Depth Convert, Channel Converter, DC Offset, Graphic Fade, Normalize, Resample, & Time Stretch.

to create a Resample preset from scratch, you use the Fields_Resample class to fill in the parameters, then set that into the Fields parameter of a SfGenericPreset object thus:


ISfFileHost file = app.CurrentFile;

SoundForge.Fields_Resample fres = new SoundForge.Fields_Resample();
fres.SampleRate = 31450;
fres.Accuracy = 2;
fres.SetRateOnly = false;
fres.Filter = true;

ISfGenericEffect fx = app.FindEffect("Resample");
SfGenericPreset preset = new SfGenericPreset("Whatever", fx);
preset.Fields = fres;
file.DoEffect(fx.Name, preset, SfAudioSelection.All, EffectOptions.EffectOnly);
file.WaitForDoneOrCancel();


Of course, a real script should be checking for failures and for CurrentFile being null.

tj

Message last edited on5/31/2005 6:40:58 PM by_TJ.
Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: Angels
Date:6/1/2005 10:30:59 AM

Tahnks TJ,

You're right the "Default Template" does work. I'm not sure why it didn't.

Thanks also for the resampling parameters. Questions:

1. can a variable be used for "fres.SampleRate" above? And what kind is it (string or ...)?

2. Can composite names like "Channel Converter" be used with a space or an underscore?

3. Are parameters counted from 0 up or as displayed in the Forge GUI?

A

Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: _TJ
Date:6/1/2005 1:00:42 PM

1. can a variable be used for "fres.SampleRate" above? And what kind is it (string or ...)?

the type is uint, an unsigned integer. you can use a variable to assign this, or you can use uint.Parse(strVariable) where strVariable is a string containing your sample rate. You should be aware that uint.Parse() will throw an exception if the string you pass it is not a valid unsigned integer.

You can learn the types and names of all of the parameters by browsing the Forge80.Script.dll using Microsoft's Visual Studio, or using a free tool called Reflector. Theres a page at the Peach Rock website that has links to a bunch of free tools useful for scripting, including Reflector. http://www.peachrock.com/software/tutorials/free-tools.html

There are a variety of ways to get your sample rate from a script argument. assuming that your Script Args is:File=my file.wav&Rate=44100. (note that the & is used to separate arguments, just like in a URL)
uint uRate;
try
{
uRate = uint.Parse(Script.Args.ValueOf("Rate"));
}
catch
{
// abort the script here, sample rate is missing or invalid.
}
or, if you want to use use a default value of 44100 when the rate is missing...
uint uRate = (uint) GETARG("Rate", 44100);

2. Can composite names like "Channel Converter" be used with a space or an underscore?

I'm not sure that I understand the question. In what context? In general, you cannot use an underscore where we expect to find a space. But how you go about using composite names without having them split into parts by a parser depends on where you are using it. For Script Args, this is a non-issue, because space isn't treated as a separator, & is.

3. Are parameters counted from 0 up or as displayed in the Forge GUI?

No, it's not that simple. 0 is sort of a special case that gives you the default settings of the Effect. Other positive integers will give you the built in presets, but not necessarily in the order that they appear in the GUI. They will be in the same order that they show up in the ISfGenericEffect.Presets collection. But it isn't wise to depend on any value other than 0, we don't promise to preserve the indexes in future versions - just use the preset names instead.

tj


Message last edited on6/1/2005 1:05:25 PM by_TJ.
Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: Angels
Date:6/1/2005 2:48:19 PM

OK!

1. Got it working. The error trapping is just like the Argument null catching (return "comment"). Cool. I also used Reflector and notice that for "Fields_Resample", "Accuracy : Int32" reads "set_Accuracy(Int32):Void". Does this mean that any setting submitted is ignored?
This refers to item 3 below.

2. I meant "Must" instead of "Can" sorry. So spaces it is.

3. In fact, I just wanted to know if values are entered from 0 up or from 1 up, for the "Accuracy" setting (it's 1 to 4 in the GUI, but in code it's often seen as 0 to 3). But I tried running different numbers for Resample "Accuracy", and it doesn't seem to matter what number is used (even multi-digit), so I assume it is in fact ignored. Can you at least confirm which accuracy level is being used when the effect is invoked this way? I would hope it's "High".

Thanks again.

A


Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: _TJ
Date:6/1/2005 7:02:49 PM

The range for values for the Fields_Resample (or for any of the Fields_xxx objects) depends on the field. There is no set rule.

However, you can use this code

ISfGenericEffect fx = app.FindEffect("Resample");
SoundForge.Fields_Resample fres = new SoundForge.Fields_Resample();
fres.SampleRate = uRate;
fres.Accuracy = 2;
fres.SetRateOnly = false;
fres.Filter = true;
SfGenericPreset preset = new SfGenericPreset("Name", fx);
preset.Fields = fres;

// show the Dialog using the values of the preset
fx.ChoosePreset(IntPtr.Zero, preset);


to see what the values you set show up as in the GUI.
or this code


string strPresetName = "My Preset";
ISfGenericEffect fx = app.FindEffect("Resample");
ISfGenericPreset preset = fx.GetPreset(strPresetName);
Fields_Resample fres = preset.Fields as Fields_Resample;
DPF("Rate {0}", fres.SampleRate);
DPF("Accuracy {0}", fres.Accuracy);
DPF("SetOnly {0}", fres.SetRateOnly);
DPF("Filter {0}", fres.Filter);

To print out the values the of the preset with the name "My Preset"

Or, replace fx.GetPreset() above with

ISfGenericPreset preset = fx.ChoosePreset(IntPtr.Zero, "My Preset");

and the GUI will show the settings of "My Preset" and then return whatever
the user sets the parameters to. So you can learn ranges of parameters
for the effects by experimentation

tj


Message last edited on6/1/2005 7:04:28 PM by_TJ.
Subject:RE: Newbie to Scripting: using Forge from CLI
Reply by: Angels
Date:6/2/2005 6:58:56 AM


The script runs perfectly: I can clearly test what parameter settings do.

Thanks again, TJ, for your generous assistance.

Angels


Go Back