Community Forums Archive

Go Back

Subject:Another newbie: error handling from CLI
Posted by: ghova
Date:6/15/2005 12:07:14 PM

Hi everyone...

Apologies for the length of this post, but I want to be as specific about my problem as I can. :)

My company has used Sound Forge ever since version 4.5. The scripting features of 8.0 are very exciting, and I'm trying to implement them in our automated batch environment.

A few important notes here. First off, our automated batch environment needs to be hands-free. That means it needs to be able to handle as many errors or exceptions without human intervention as possible.

A little about me: I've programmed in VB on and off for the past few years, and I'm completely new to .NET. I feel most comfortable with VB, but I'm by no means an expert at coding. So if my code looks strange or sloppy, it's because I'm a bit of a hack. :)

I'm trying to set up a script in which Sound Forge accepts a command-line arguement (using our own custom watch-folder software from our current batch environment) to open a file, automatically process it, save it, and close it. The watch-folder software would feed Sound Forge another command line once it sees another file, and so on.

(Why not just code watch-folder capability into my script? I tried... but as I said, I'm not the most experienced programmer around, and I encountered too many roadblocks. If anyone can show me how to do this, I'd appreciate it greatly.)

I've studied Angels' CLI thread pretty intently, and SonyTJ's reply has helped me get very far. But I finally hit a roadblock. Here it is...

Say we've got a file called "Doom.wav" that's a corrupted .wav file (for my purposes, I took a text file and renamed it). We run the following script directly from Sound Forge (apologies to the C#-ers in here, but as I said, I'm most comfortable with VB-related code)...

Public Class EntryPoint
Public Function Begin(app as IScriptableApp)

'begin here
Dim UserFile as ISfFileHost
Dim ioInput as string
ioInput = "doom.wav"
try
UserFile=app.OpenFile(ioInput,false,false)
catch ex as Exception
messagebox.show (ex.message) 'Obviously, in an automated environment, this would be a log entry, not a modal window
exit function
end try

End Function

This will work as intended; the "catch" statement will receive the thrown exception, the messagebox will appear, and the script will end as normal.

Here's my problem: I'm not running the script from within SF, but starting it from a command line. So we'll change our code thusly...

Public Class EntryPoint
Public Function Begin(app as IScriptableApp)

'begin here
Dim UserFile as ISfFileHost
Dim ioInput as string
Dim ioArgs as string

'I had a hard time working with Script.Args and multiple arguments, so I've just been parsing it from RawArgs
'I suppose that's a post for another day. :)
ioArgs = Script.RawArgs
ioInput = ioArgs.Substring(ioArgs.IndexOf("input"), ioArgs.IndexOf("output") - ioArgs.IndexOf("input") -1)
ioInput = ioInput.Remove (0,6)

try
UserFile=app.OpenFile(ioInput,false,false)
catch ex as Exception
messagebox.show(ex.message)
exit function
end try

End Function

And now we'll send SF a command line...

forge80.exe /Script:"C:\Program Files\Sony\Sound Forge 8.0\Script Menu\Exception Test.vb"?input=doom.wav_output=doom.wav

Well, the messagebox will come up again. If you clear the messagebox, all will appear normal. But right away, let's try passing a command line for a working .WAV file...

forge80.exe /Script:"C:\Program Files\Sony\Sound Forge 8.0\Script Menu\Exception Test.vb"?input=working.wav_output=working.wav

And here's my problem; the file opens, but a modal dialog (NOT the messagebox we coded!) immediately comes up from Sound Forge saying "Warning: An error occured during the current operation. The file is an unsupported format." If you open up the Details pane, you'll see that it's actually complaining about the doom.wav file... even though it was supposedly handled by the try/catch statements!

Since this dialog is modal, no work will be done on the proper .WAV file until the dialog is cleared. And that's my problem; I need the program to automatically work around any corrupt files without human intervention.

As you can see, this is only a problem when the script is invoked from a command line.

Can anyone help?

Thanks to everyone, and especially to Sony for these exciting scripting capabilities!

~Gil

Message last edited on6/15/2005 12:55:57 PM byghova.
Subject:RE: Another newbie: error handling from CLI
Reply by: _TJ
Date:6/15/2005 2:26:26 PM

well, first of all, your closing quote is in the wrong place for your script command line.

It should be:


forge80.exe /Script:"C:\Program Files\Sony\Sound Forge 8.0\Script Menu\Exception Test.vb?input=working.wav_output=working.wav"

or

forge80.exe "/Script:C:\Program Files\Sony\Sound Forge 8.0\Script Menu\Exception Test.vb?input=working.wav_output=working.wav"

Although, I'm not, at this point convinced that this is the cause of your problem.

Also, if you use the ampersand as the argument separator, rather than an underscore, you won't have to do your own argument parsing.

input=working.wav&output=working.wav

will be broken up into two args in the Script.Args collection

Dim ioInput as string = Script.Args.ValueOf("input")
Dim ioOutput as string = Script.Args.ValueOf("output")
DPF(ioInput)
DPF(ioOutput)


It's gonna take me a bit of time to setup and try and replicate your problem, I'll be posting back more info once I have it.

tj

Message last edited on6/15/2005 2:27:28 PM by_TJ.
Subject:RE: Another newbie: error handling from CLI
Reply by: ghova
Date:6/15/2005 3:02:37 PM

> well, first of all, your closing quote is in the wrong place for your script command line.

Right you are. Actually, it's sloppy posting on my part. :) Sorry about that.

> Also, if you use the ampersand as the argument separator, rather than an underscore, you won't have to do your own argument parsing.

Yes, that was the first thing I tried. It seemed to parse the entire statement as the first argument. So if I tried this...

input=working.wav&output=working.wav

... the Script.Args.ValueOf("input") would equal "input=working.wav&output=working.wav" and the Script.Args.ValueOf("output") would equal "".

But that's a minor problem, as the raw text parsing works for now. Of course, it's probably something I did wrong... but I'm much more concerned about the command-line/try...catch issue, as that's my current roadblock. Perhaps once we figure out what's causing that modal dialog to display, then I can start a seperate thread and post details on my Args issue. It wouldn't surprise me that once I split it out into its own script, I'll figure out what I did wrong. :)

Thank you very much for your help, TJ! It's tremendously appreciated, and I can't wait to get this thing bulletproof for our batch automation environment!

~Gil

Subject:RE: Another newbie: error handling from CLI
Reply by: _TJ
Date:6/15/2005 3:44:52 PM

After some investigation, I have determined that there is no way for you to suppress error messages if you run a script from the command line and it ends up failing to load a file.

I wasn't able to reproduce exactly what you described. What I see is that that scripts' message box shows up first, and then (after the script exits) , the standard Sound Forge error message box.

You will get the standard Sound Forge error message box in any case where the script tried to do something that failed, even if the script eats the resulting exception. This always happens when scritpts are run from the command line, because we have no way of determing that the error has been reported already. This is not a bug, although I can certainly see why you would like to supress this message box in your application.

I will add a note to try and get some sort of error message suppression method into the next version of Sound Forge scripting.

In a later post, I'll will demonstrate a basic scaffolding for using watch folders, I would suggest that you try going down that route instead. So long as your script doesn't exit, Sound Forge will not show any error message boxes.

tj




Message last edited on6/15/2005 3:46:50 PM by_TJ.
Subject:RE: Another newbie: error handling from CLI
Reply by: _TJ
Date:6/15/2005 3:50:17 PM

Here's your script, but with corrected Script.Args use.

using Script Args:
input=doom.wav&output=working.wav

Imports System
Imports System.IO
Imports System.Windows.Forms
Imports SoundForge

Public Class EntryPoint
Public Function Begin(app as IScriptableApp)

Dim ioInput as string = Script.Args.ValueOf("input")
Dim ioOutput as string = Script.Args.ValueOf("output")
Dim UserFile as ISfFileHost

DPF("input is '{0}' output is '{1}'", ioInput, ioOutput)

try
UserFile=app.OpenFile(ioInput,false,false)
catch ex as Exception
messagebox.show(ex.message)
exit function
end try

End Function

Function FromSoundForge(app as IScriptableApp)
ForgeApp = app
app.SetStatusText(String.Format("Script '{0}' is running.", Script.Name))
Begin(app)
app.SetStatusText(String.Format("Script '{0}' is done.", Script.Name))
End Function
Public ForgeApp as IScriptableApp
Public Function DPF(sz)
ForgeApp.OutputText(sz)
End Function
Public Function DPF(sz,o)
ForgeApp.OutputText(System.String.Format(sz,o))
End Function
Public Function DPF(sz,o,o2)
ForgeApp.OutputText(System.String.Format(sz,o,o2))
End Function
Public Function DPF(sz,o,o2,o3)
ForgeApp.OutputText(System.String.Format(sz,o,o2,o3))
End Function

End Class 'EntryPoint

Subject:RE: Another newbie: error handling from CLI
Reply by: _TJ
Date:6/15/2005 3:52:38 PM

And here's the same script in C#


using System;
using System.Windows.Forms;
using SoundForge;

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

string strInput = Script.Args.ValueOf("input");
string strOutput = Script.Args.ValueOf("output");
ISfFileHost userfile;

DPF("input is '{0}' output is '{1}'", ioInput, ioOutput);

try
{
userfile = app.OpenFile(strInput, false, false);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}

}

public void FromSoundForge(IScriptableApp app) {
ForgeApp = app; //execution begins here
app.SetStatusText(String.Format("Script '{0}' is running.", Script.Name));
Begin(app);
app.SetStatusText(String.Format("Script '{0}' is done.", Script.Name));
}
public static IScriptableApp ForgeApp = null;
public static void DPF(string sz) { ForgeApp.OutputText(sz); }
public static void DPF(string fmt, object o) { ForgeApp.OutputText(String.Format(fmt,o)); }
public static void DPF(string fmt, object o, object o2) { ForgeApp.OutputText(String.Format(fmt,o,o2)); }
} //EntryPoint

Subject:RE: Another newbie: error handling from CLI
Reply by: ghova
Date:6/15/2005 4:33:27 PM

> You will get the standard Sound Forge error message box in any case where the script tried to do something that failed, even if the script eats the resulting exception. This always happens when scritpts are run from the command line, because we have no way of determing that the error has been reported already. This is not a bug, although I can certainly see why you would like to supress this message box in your application.

I will add a note to try and get some sort of error message suppression method into the next version of Sound Forge scripting.

====

It's amazing what kind of feature requests end-users come up with, huh? :)

Seriously, I appreciate the detective work and resulting code whirlwind. I'll try out the watch folders you put up in the other thread. I'm also curious to try your Args and see how it goes. If I can't get it to work, I'll post it in another thread for posterity's sake.

Again, thanks for all your hard work. This is great stuff!

~Gil

Subject:RE: Another newbie: error handling from CLI
Reply by: ghova
Date:6/17/2005 8:57:38 AM

It's been a couple of days, and I've been implementing the watch folders into our scripts.

Unfortunately, it looks like this modal dialog problem extends further than we thought. It seems to pop up whenever Sound Forge encounters a bad file, and stops the script cold.

Here's a sample script that shows my problem. Say you have two files in the folder D:\TEST. One is a proper .wav file called WORKING.WAV, and the other is a corrupt .wav file called DOOM.WAV. Again, to replicate a corrupt .wav file, I just took any text file and renamed it DOOM.WAV.


Imports System
Imports System.IO
Imports System.Windows.Forms
Imports SoundForge

Public Class EntryPoint
Public Function Begin(app as IScriptableApp)
dim ioInput as string
dim x as integer
dim UserFile as isfFileHost
'begin here

try
for x = 1 to 2
select x
case 1
ioInput="d:\test\doom.wav"
case 2
ioInput="d:\test\working.wav"
end select
DPF("Trying to open " & ioInput)
UserFile=app.OpenFile(ioInput,false,false)
UserFile.Close(CloseOptions.DiscardChanges)
next
catch ex as exception
DPF("Error opening " & ioInput)
dim tempPath as string = Path.GetDirectoryName(ioInput) & "\" & "BadFiles"
if Directory.Exists(tempPath) = false then Directory.CreateDirectory(tempPath)
tempPath = tempPath & "\" & Path.GetFileName(ioInput)
if File.Exists(tempPath) = true then File.Delete(tempPath)
File.Move(ioInput, tempPath)
exit function

end try

End Function

Function FromSoundForge(app as IScriptableApp)
ForgeApp = app
app.SetStatusText(String.Format("Script '{0}' is running.", Script.Name))
Begin(app)
app.SetStatusText(String.Format("Script '{0}' is done.", Script.Name))
End Function
Public ForgeApp as IScriptableApp
Public Function DPF(sz)
ForgeApp.OutputText(sz)
End Function
Public Function DPF(sz,o)
ForgeApp.OutputText(System.String.Format(sz,o))
End Function
Public Function DPF(sz,o,o2)
ForgeApp.OutputText(System.String.Format(sz,o,o2))
End Function
Public Function DPF(sz,o,o2,o3)
ForgeApp.OutputText(System.String.Format(sz,o,o2,o3))
End Function

End Class 'EntryPoint


What SHOULD happen is that...

1) Sound Forge tries to open DOOM.WAV. It can't, so it creates a "BadFiles" subfolder and moves the file there.
2) Sound Forge tries to open WORKING.WAV, succeeds, and closes it.

What ACTUALLY happens is that we never get to step two; the accursed modal dialog (coming from Sound Forge, not from .NET, and saying that DOOM.WAV is an invalid file and can't be opened) appears after step 1 has been completed, even though the exception has supposedly been handled.

So it seems that the command line isn't a factor here; it's simply the action of Sound Forge stopping after encountering a corrupt file.

Now, again, I'm not an experienced programmer, so it's very likely that there's something wrong with my code.

But for my company's purposes, it is imperative that this modal dialog be supressed. If it's not, then we can't put Sound Forge 8 in our automated batch environment. This would be a shame, because other than this one showstopping roadblock, it would be absolutely perfect for our needs.

Please let me know if you can help. Thanks for everything!

~Gil

Message last edited on6/17/2005 9:01:40 AM byghova.
Subject:RE: Another newbie: error handling from CLI
Reply by: ghova
Date:6/17/2005 9:06:29 AM

Okay, okay, two problems with the above code...

1) The big blaring EXIT FUNCTION that caused the whole thing to stop.

2) Dunno if this was holding anything back, but I moved the FOR...NEXT loop out of the TRY...CATCH structure.

Updated code...

Imports System
Imports System.IO
Imports System.Windows.Forms
Imports SoundForge

Public Class EntryPoint
Public Function Begin(app as IScriptableApp)
dim ioInput as string
dim x as integer
dim UserFile as isfFileHost
'begin here
for x = 1 to 2
try
select x
case 1
ioInput="d:\test\doom.wav"
case 2
ioInput="d:\test\working.wav"
end select
DPF("Trying to open " & ioInput)
UserFile=app.OpenFile(ioInput,false,false)
UserFile.Close(CloseOptions.DiscardChanges)
catch ex as exception
DPF("Error opening " & ioInput)
dim tempPath as string = Path.GetDirectoryName(ioInput) & "\" & "BadFiles"
if Directory.Exists(tempPath) = false then Directory.CreateDirectory(tempPath)
tempPath = tempPath & "\" & Path.GetFileName(ioInput)
if File.Exists(tempPath) = true then File.Delete(tempPath)
File.Move(ioInput, tempPath)
end try
next
End Function

Function FromSoundForge(app as IScriptableApp)
ForgeApp = app
app.SetStatusText(String.Format("Script '{0}' is running.", Script.Name))
Begin(app)
app.SetStatusText(String.Format("Script '{0}' is done.", Script.Name))
End Function
Public ForgeApp as IScriptableApp
Public Function DPF(sz)
ForgeApp.OutputText(sz)
End Function
Public Function DPF(sz,o)
ForgeApp.OutputText(System.String.Format(sz,o))
End Function
Public Function DPF(sz,o,o2)
ForgeApp.OutputText(System.String.Format(sz,o,o2))
End Function
Public Function DPF(sz,o,o2,o3)
ForgeApp.OutputText(System.String.Format(sz,o,o2,o3))
End Function

End Class 'EntryPoint

What happens now is even more interesting. DOOM.WAV is moved to the BADFILES folder, and WORKING.WAV is opened. Then the modal SoundForge dialog appears. Once the dialog is dismissed, then WORKING.WAV closes.

So while I apologize humbly for my lousy coding, I'm not sure if it's just me.

Thanks again for your time!

~Gil

Message last edited on6/17/2005 9:41:45 AM byghova.
Subject:RE: Another newbie: error handling from CLI
Reply by: _TJ
Date:6/17/2005 2:08:19 PM

Ok. I see the problem. It turns out that there is a workaround in this case,
but it only defers the issue until later. If you pass true as the last argument of
app.OpenFile(), then we won't try to build a peak file, and the stored error won't
get picked up as an error in the peak building attempt.

But like I said, all that does is to push the problem off until later.

The basic problem is that the error from trying to open doom.wav is going to stick around and interfere with error returns until it gets cleared. And it can only get
cleared by being reported (or by the Script Editor window when it does a compile).

So you can get this code to work. (i.e. sorting good files from bad). but you will definitely get an error popup after the script exits. Or you will get an error popup if you try to do any processing (i.e. calling file.DoEffect()). Basically, anything that shows progress down in the status bar is going to pick up that pending error report and show a message box. Only then will the error get cleared.

tj


Subject:RE: Another newbie: error handling from CLI
Reply by: ghova
Date:6/17/2005 2:22:00 PM

So you can get this code to work. (i.e. sorting good files from bad). but you will definitely get an error popup after the script exits. Or you will get an error popup if you try to do any processing (i.e. calling file.DoEffect()). Basically, anything that shows progress down in the status bar is going to pick up that pending error report and show a message box. Only then will the error get cleared.

Unfortunately, because we need to process these files, the next step after Opening would be a fileDoEffect(). And since there is always the possibility of a corrupt file entering our automated system (we allow outside editors access to our encoding system, and you never quite know what you're going to get from them), we need to be able to work around modal dialogs without human intervention.

I might be able to work around this another way: by going back to the command-line code, only allowing .WAV files into the system, and having our custom software screen out anything without a valid WAV header (which it can already do), and pass the command line to Sound Forge.

However, we are handcuffed by this. Having SF8 open the files natively gives us much more flexibility, and it allows us to work with almost any sound file. The workaround I explained creates a much more complex, fragile, and herky-jerky system; making our system tighter and more elegant was supposed to be the point of migrating to SF8.

If there is any way that this issue can be addressed in a future patch (i.e. some switch that could supress these modal dialogs), it would be greatly appreciated.

Thanks again for your help, TJ!

~Gil

Message last edited on6/17/2005 2:22:44 PM byghova.

Go Back