Community Forums Archive

Go Back

Subject:Hyperthreading problem with SF script
Posted by: timaddy
Date:4/28/2008 7:37:40 AM

Hi,

I wrote a script some time ago which fixes glitches on wav files when the start and width of the glitches are known. Recently we've noticed a few problems with crashing and once in a while with a directory path being corrupted. The program works by passing in 4 parameters which are:

the directory path
the wav filename
the start position in samples of an audio glitch
the width of the audio glitch

when this program is run in a loop on a multiprocessor (2 CPU or 4 CPU Pentium xeons) then the program crashes (it completes the glitch fixing/interpolation operation but generates a soundforge crash window). When the exact same code is run on a single CPU machine with no hyperthreading (3GHz pentium) then there are no problems with crashing or (so far) path corruption. I have also run this on Soundforge 8 and 9 with the same results.

The program generates log files from soundforge and the logs are all fine (the glitch fix script is fine and we also pass in a close script. to close soundforge.exe down. See the scripts below.

The glitch script code using external parameters is:

//*****************************************************************************
//* Start of Code. *
//*****************************************************************************

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

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

string szPath = GETARG("Dir", ""); //Directory input argument. Type "" to leave blank
string szFilename = GETARG("File", "");//Filename input argument


int szStart = GETARG("glitchstart",1);//Input parameter 1 that defines the start point of the glitch
int szWidth = GETARG("glitchwidth",2);//Input parameter 2 that defines the width of the glitch to be processed

SfStatus result = SfStatus.Success;

//Add in a check that Dir has been set (if not set a default value)
if (null == szPath)
{
szPath = @"C:\";
DPF("NO DIRECTORY PARAMETER HAS BEEN SET AS AN INPUT PARAMETER. USE /Script:<path_to_script?Dir=<dir_path> WHEN CALLING SF");
}

string szWavFile = Path.Combine(szPath, szFilename) + ".wav";//concatenated filename based on the path, filename and .wav
DPF("{0} check the WAV File variable contents", szWavFile);

//#######################################################################
//Create the output file path and name to write the WAV output and log file
//#######################################################################
string szWavOutFile = szFilename;//output filename
string szOPDir = szPath + "\\dr\\";
if ( ! Directory.Exists(szOPDir))
{
Directory.CreateDirectory(szOPDir); // make sure that the directory exists...
}

//####################################################################
//check that the output file & log file doesn't already exist.
//If it does then add a number "_<ccFileExt>" to the name
//create the full path to the output directory
//####################################################################
szWavOutFile = Path.Combine(szOPDir, szWavOutFile) + ".wav";//adds extra output directory to each file
string szWavOutLogFile = Path.GetFileNameWithoutExtension(szWavOutFile);
if (File.Exists(szWavOutFile))
{
szWavOutFile = (Path.Combine(szOPDir, (Path.GetFileNameWithoutExtension(szWavFile))) + ".wav");
szWavOutLogFile = Path.GetFileNameWithoutExtension(szWavOutFile);
}
else
{
result = SfStatus.Fail;
}
DPF("Output filename and directory debug {0}", szWavOutFile);
szWavOutLogFile = Path.Combine(szOPDir, szWavOutLogFile) + ".log";//adds extra output directory (\\dr\\ to each file
StreamWriter sw = new StreamWriter(szWavOutLogFile);
if ( ! File.Exists(szWavFile))
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error");
sw.WriteLine("Warning: Input File Does Not Exist with name : \n {0}", szWavFile);
sw.WriteLine("####################################################################################");
result = SfStatus.Fail;
}

//###########################################################################################
// Write out the Input Directory path that is passed to Soundforge to check it's ok
//###########################################################################################

sw.WriteLine(" Input Directory Path from DIR parameter = {0}", szPath);

//############################################################################################
//check that the start and width parameters are not 0 (if they are then generate an exception)
//############################################################################################
if (szStart == 0)
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: Glitch Removal Process Failed");
sw.WriteLine("fatal: An Error has occurred due to the start parameter having a value of 0");
sw.WriteLine("####################################################################################");
result = SfStatus.Fail;
sw.Close();//close the log file
}
else
{
sw.WriteLine("glitch start parameter has a valid value of {0}", szStart);
}

//###########################################################################################
//check that the glitch width parameter is valid
//###########################################################################################
if (szWidth == 0)
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: Glitch Removal Process Failed");
sw.WriteLine("fatal: An Error has occurred due to the Width parameter having a value of 0");
sw.WriteLine("####################################################################################");
result = SfStatus.Fail;
sw.Close();//close the log file
}
else
{
sw.WriteLine("Glitch width parameter has a valid value of {0}", szWidth);
}

//process the file using the audio restoration effect
result = ProcessFile(app, szWavFile, szWavOutFile, szWavOutLogFile, sw, szStart, szWidth);

DPF("~ - {0}", result);
if (result != SfStatus.Success)
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: Glitch Removal Process Failed");
sw.WriteLine("fatal: An Error has occurred whilst processing the audio file");
sw.WriteLine("####################################################################################");
sw.Close();//close the log file
}
else
{
sw.WriteLine(" ");
sw.WriteLine("####################################################################################");
sw.WriteLine("Glitch Removal Completed successfully");
sw.WriteLine("####################################################################################");
}
sw.Close();//close the log file
} // Begin

//Function used to process the WAV input file and call the audio glitch removal function

public SfStatus ProcessFile(IScriptableApp app, string szWavFile, string szWavOutFile, string szWavOutLogFile, StreamWriter sw,int szStart, int szWidth)
{
SfStatus result = SfStatus.Success;

try
{
ISfFileHost fileIn = app.OpenFile(szWavFile, false, true);//not read-only, do not allow soundforge window

//Check that the file is not empty, if it is then set the status to fail
//Check that the file data length is 8 or more samples (minimum window size for glitch removal)
if ((null == fileIn) | (fileIn.Length <= 8)) {
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: ");
sw.WriteLine("fatal: Input file is Empty");
sw.WriteLine("####################################################################################");
return SfStatus.Fail;
}

//Restore the present file using the built in glitch removal function
Int64 ccLength = fileIn.Length;
Int64 ccGlitchPos = 0;
Int64 ccPosDiff = 1;//Sample Position Difference between glitches
Int64 ccEnd = 0;//End of Interpolation window sample value

ccEnd = szStart + szWidth;

//Set the audio selection region
SfAudioSelection AllAudio = new SfAudioSelection(szStart,ccEnd);//Select the whole audio waveform (0 = start, -1 = end)

DPF("Value of szStart = {0} ", szStart);
DPF("Value of ccEnd = {0} ", ccEnd);

//undertake glitch removal
ccGlitchPos = szStart;//set the start glitch position

DPF("RUNNING FIRST PASS GLITCH REMOVAL");
sw.WriteLine("RUNNING FIRST PASS GLITCH REMOVAL");
//FIRST PASS GLITCH REMOVAL = loop until no more glitches are found
for (Int64 ccPos = szStart; ccPos < ccLength; ccPos += ccPosDiff)
{
if (result == SfStatus.Success)
{
SfAudioSelection GlitchReg = new SfAudioSelection(szStart, szWidth);//Create the Interpolation window
DPF("Value of szStart in First Pass = {0} ", szStart);
DPF("Value of ccEnd in first Pass= {0} ", ccEnd);
sw.WriteLine("Valud of szStart = {0}", szStart);
sw.WriteLine("Valud of ccEnd = {0}", ccEnd);
//select the audio selection from the start sample point of the glitch and the end point based on the glitch width + start
SfAudioSelection asel = new SfAudioSelection(szStart, ccEnd);

fileIn.Window.SetSelectionAndScroll(szStart, szWidth, DataWndScrollTo.Nearest);//added by TPA to move window
app.DoMenuAndWait ("Tools: Repair Interpolate", true);
//remove 1 from posDiff (this allows looping based on the default value of ccPosDiff
ccPosDiff = ccPosDiff - 1;
if (ccPosDiff == 0)//Loop until no further glitches found
{
DPF("PARAMETER BASED GLITCH REMOVAL COMPLETED");
break;
}

}
else
{
DPF("ERROR HAS OCCURRED DURING FIRST PASS LOOP. SFStatus is not .Success. Either File Loading Error or Glitch Detection Error");
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: ");
sw.WriteLine("Warning: Problem has occurred during FIRST PASS LOOP. SFStatus is not .Success. Either File Loading Error or Glitch Detection Error");
sw.WriteLine("####################################################################################");
result = SfStatus.Fail;
break;
}
}//end of for loop

//##############################################################################
//Write out the new audio file
//##############################################################################
ISfFileHost fileOut = fileIn.NewFile(new SfAudioSelection(0,-1));//select all of the current AudioSelection? Check this

//Select all of the audio from the present file, then overwrite the fileOut with this from fileIn
SfAudioSelection aselAllOut = new SfAudioSelection(0,-1);
fileOut.OverwriteAudio(0, 0, fileIn, aselAllOut);

fileOut.RenderAs(szWavOutFile, fileOut.SaveFormat.Guid, 0, new SfAudioSelection(fileOut), RenderOptions.RenderOnly);
result = fileOut.WaitForDoneOrCancel();

//#############################################################################
//Write out the audio file statistics and the audio restore info
//#############################################################################

//####################################################################
//Get the Statistics for the input and output files
//####################################################################
sw.WriteLine("####################################################################################");
sw.WriteLine("Input File Data Format & File Length");
sw.WriteLine(" Sample Rate, SampleType, Number of Channels = (" + fileIn.SampleRate + "," + fileIn.SampleType + "," + fileIn.Channels + ")");
sw.WriteLine("Input File Length (samples) = {0}", fileIn.Length);
sw.WriteLine("####################################################################################");
sw.WriteLine("Output File Data Format & File Length");
sw.WriteLine(" Sample Rate, SampleType, Number of Channels = (" + fileOut.SampleRate + "," + fileOut.SampleType + "," + fileOut.Channels + ")");
sw.WriteLine("Output File Length (samples) = {0}", fileOut.Length);
sw.WriteLine("####################################################################################");

fileIn.Close(CloseOptions.DiscardChanges);//close the input file
fileOut.Close(CloseOptions.DiscardChanges);//close the output file
}
catch(Exception e)
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error:");
sw.WriteLine("The following exception was caught:\n{0}", e);
sw.WriteLine("####################################################################################");
return SfStatus.Fail;
}

return result;
}

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)); }
public static void DPF(string fmt, object o, object o2, object o3) { ForgeApp.OutputText(String.Format(fmt,o,o2,o3)); }
public static string GETARG(string k, string d) { string val = Script.Args.ValueOf(k); if (val == null || val.Length == 0) val = d; return val; }
public static int GETARG(string k, int d) { string s = Script.Args.ValueOf(k); if (s == null || s.Length == 0) return d; else return Script.Args.AsInt(k); }
public static bool GETARG(string k, bool d) { string s = Script.Args.ValueOf(k); if (s == null || s.Length == 0) return d; else return Script.Args.AsBool(k); }
} //EntryPoint


The close process script uses the method described in this forum to close a process:

Process curr = Process.GetCurrentProcess();
curr.CloseMainWindow();:


As an example to show the problem (the exact code is all built as part of a C++ project ) but the same problem occurs using a dos batch file. The code below shows how the parameters are passed in to soundforge:


"c:\Program Files\Sony\Sound Forge 8.0\Forge80.exe" /NoDefSession /NoLogo /Script:"<path_to_glitchfixscript>\Audio_Glitch_removal_extparam_.cs"?dir="<path_audio_arc>\audio_src&File="wav_input_filename"&glitchstart=18&glitchwidth=18" /Script:"<path_to_close_script>\close_sf.cs"


The actual batch file run the above soundforge call in a loop multiple times.

Are there any known issues with Hyperthreading? Do you have any ideas as to whether path corruption is a known problem or can occur when passing external paths in to soundforge? Is soundforge 8 or 9 designed to work on hyperthreading enabled machines?

Thanks for any help

Regards

Tim

Some addition details for the path corruption problem:

I've been running tests and the soundforge debug info that appears when the path gets corrupted is enclosed as below:

System.TypeInitializationException: The type initializer for "Microsoft.CSharp.CSharpCodeGenerator" threw an exception. ---> System.InvalidProgramException: Common Language Runtime detected an invalid program.
at Microsoft.CSharp.CSharpCodeGenerator..cctor()
--- End of inner exception stack trace ---
at Microsoft.CSharp.CSharpCodeGenerator..ctor()
at Microsoft.CSharp.CSharpCodeProvider..ctor()
at SoundForge.CodeDomScriptManager..ctor(EngineType eType)
at SoundForge.ScriptHost.RunScript(String szFile, String szSourceText, EngineType eType, Boolean fCompileOnly, Boolean fDebug)
System.TypeInitializationException: The type initializer for "Microsoft.CSharp.CSharpCodeGenerator" threw an exception. ---> System.InvalidProgramException: Common Language Runtime detected an invalid program.
at Microsoft.CSharp.CSharpCodeGenerator..cctor()
--- End of inner exception stack trace ---
at Microsoft.CSharp.CSharpCodeGenerator..ctor()
at Microsoft.CSharp.CSharpCodeProvider..ctor()
at SoundForge.CodeDomScriptManager..ctor(EngineType eType)
at SoundForge.ScriptHost.RunScript(String szFile, String szSourceText, EngineType eType, Boolean fCompileOnly, Boolean fDebug)
The file C:\Apps_local\V303\Files\Sony\Sound could not be opened.
The file C:\Apps_local\V303\Forge could not be opened.
The file C:\Apps_local\V303\8.0\Forge80.exe could not be opened.

The input file path was not C:\Apps_local\V303\Files\Sony\Sound when set by the input parameter.

This problem is urgent so if someone could have a look at the message above that would be greatly appreciated.

Regards

Tim Addy

Message last edited on5/2/2008 6:36:15 AM bytimaddy.
Subject:RE: Hyperthreading problem with SF script
Reply by: _TJ
Date:5/6/2008 4:38:07 PM

There are no KNOWN problems with Hyperthreading in Sound Forge. But what you are trying to do is pretty likely to trigger a problem if there is one.

The error message tells us that the script is failing to compile. Since this is only happening some of the time, the script probably isn't the problem. It could be a problem with .net trying to do two things at once, or it could be a problem with Sound Forge trying to do two things at once.

Because you are using a Batch command to run Sound Forge, tell it to run a single script, then exit. Sound Forge is constantly starting up and shutting down.

Since only 1 instance of Sound Forge can be running at a time, I would guess that on the multiprocessor machine, you are running into a situation where Sound Forge is trying to exit and start up at the same time. (The first line of the batch file has returned, but Sound Forge isn't really completely gone yet when the second line of the batch file executes and starts a new copy of Sound Forge. the two copies then interfere with each other).

I would imagine putting a
sleep 1
command between each run of Sound Forge in you batch file will give Sound Forge time to shut down.

But, since constantly starting and stopping Sound Forge takes quite a bit of time all by itself, a better solution would be to change your script to process multiple files before exiting.

tj

Subject:RE: Hyperthreading problem with SF script
Reply by: timaddy
Date:5/16/2008 12:43:24 PM

Hi TJ (Tony),

Thanks for the suggestions. I would like to point out that I think Soundforge is a fantastic audio editor and has very powerful scripting capabilities compared to other professional audio editing tools if you spend some time learning csharp (or other languages).

I have tried a number of things that you have suggested and re-written my scripts to use an XML reader to load in 4 parameters from a file : DIR - the directory of the file to processs, File - the filename, glltchstart - the start position of the glitch as a sample position and glitchwidth - the width of the glitch to process. Then a comment is used to indicate that this is the end of the set of parameters for 1 glitch fix run and at the end of the file the CDATA is used to stop the present run.

The process then works fine. But as part of this process I need to be able to process a whole series of files, then shutdown soundforge and then glitch repair a whole load more files. Unfortunately I still get crashes/exception where the application has problems running the csharp script. There is a delay in the batch script to wait in between soundforge shutting down and restarting.

The new XML based script is shown below (I apologies upfront for the XML loader as it is not my best bit of coding as it uses a fixed XML format per file loop (see the example XML file below) :)

I hope that other people find this example code useful to explain how XML can be used and if anyone else with more XML knowledge has any suggestions to improve it then I will gladly add these updates.



//*****************************************************************************
//
// <<Audio Glitch Removal script with external parameters for Soundforge>>
//
// <<Audio_Glitch_Removal_extparam>>.cs
//
//******************************************************************************
// DESCRIPTION:
// NOTE: This script requires Sound Forge 8.0a or higher to run.
// Requires IScriptableApp.Win32Window, which is not available in Sound Forge 8.0
//
// This script loads in only the wav that is set by an XML input file
// (specified by external parameters
// Added Method to allow a directory to be set via a command line
// Added Method to set the filename via the command line
// Modified fileOpen to not create .sfk intermediate files
// Added debugging features and output to log file
//
// Revision History
// ----------------
//
// Date Name Initial Revision
//
// $Log: $
//
//*****************************************************************************

//*****************************************************************************
//* System Include Files *
//*****************************************************************************

// None.


//*****************************************************************************
//* Local Include Files *
//*****************************************************************************

// None.


//*****************************************************************************
//* Macro Definitions *
//*****************************************************************************

// None.


//*****************************************************************************
//* Global Data *
//*****************************************************************************

// None.


//*****************************************************************************
//* Local Function Declarations *
//*****************************************************************************

// None.


//*****************************************************************************
//* Local Data. *
//*****************************************************************************

// None.


//*****************************************************************************
//* Start of Code. *
//*****************************************************************************

using System;
using System.IO;
using System.Xml;
using System.Windows.Forms;
using SoundForge;
using System.Diagnostics;
using System.Threading;

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

string szXMLPath = GETARG("Dir", ""); //Directory input argument. Type "" to leave blank
string szXMLFilename = GETARG("File", "");//Filename input argument

//Variable definitions
string szPath = "";
string szFilename ="";
//string szXMLVer ="";
int szStart = 0;
int szWidth = 0;
int count =0;
int EndXMLParse = 0;
int ProcessGlitch = 0;

string contents = "";

DPF("START READING THE XML IN");
//Using the input DIR and file parameters create the XML input filename
DPF("Set the szXMLPath variable {0}", szXMLPath);
DPF("Set the szXMLFilename variable {0}", szXMLFilename);
string szXMLInFile = Path.Combine(szXMLPath, szXMLFilename) + ".xml";//adds extra output directory to each file
DPF("Set the szXMLInFile variable {0}", szXMLInFile);
DPF("Read the stream");

XmlTextReader reader = new XmlTextReader (szXMLInFile);
DPF("LOADED in XML parameters");

//#################################
//begin XML text reader while loop
//#################################
while (reader.Read())
{
DPF("XmlTextInputValue reader.Name = {0} and reader.Value {1}", reader.Name, reader.Value);
DPF("count value = {0}", count);

reader.MoveToContent();
//Print any XML that is of type text
if (reader.NodeType == System.Xml.XmlNodeType.Text)
contents += reader.Value + "\n";

Console.Write(contents);

//Check that the end element of a file is not found
switch (reader.NodeType)
{
case XmlNodeType.Element:
Console.Write("<{0}>", reader.Name);
break;
case XmlNodeType.Text:
Console.Write(reader.Value);
DPF("NodeType.text - reader.Value = {0}", reader.Value);
//first XML directory name parameter
if (count == 0)
{
szPath = reader.Value;
//count = count +1;
DPF("INPUT DIRECTORY PARAMETER - COUNT 1 = {0}", szPath);
}

//first XML Filename parameter
if (count == 1)
{
szFilename = reader.Value;
//count = count +1;
DPF("INPUT Filename PARAMETER - COUNT 1 = {0}", szFilename);
}

//glitch start position
if (count == 2)
{
DPF("Entered Glitch Start count = 2");
szStart = Convert.ToInt32(reader.Value);
//count = count +1;
DPF("GLITCH START POSITION - COUNT 2 = {0}", szStart);
}

//glitch width position
if (count == 3)
{
DPF("Entered Glitch Start count = 3");
szWidth = Convert.ToInt32(reader.Value);
DPF("GLITCH WIDTH - COUNT 13 = {0}", szWidth);
}
DPF("count value = {0}", count);
break;
case XmlNodeType.CDATA:
Console.Write("<![CDATA[{0}]]>", reader.Value);
EndXMLParse = 1;//Detected end of XML input file
DPF("CDATA XML type found - FOUND THE END OF THE XML INPUT FILE");
break;
case XmlNodeType.ProcessingInstruction:
Console.Write("<?{0} {1}?>", reader.Name, reader.Value);
break;
case XmlNodeType.Comment:
Console.Write("<!--{0}-->", reader.Value);
DPF("NodeType.Comment - reader.Value = {0}", reader.Value);
count = 0;
break;
case XmlNodeType.XmlDeclaration:
Console.Write("<?xml version='1.0'?>");
DPF("NodeType.XMLDeclaration =<?xml version='1.0'?>");
break;
case XmlNodeType.Document:
break;
case XmlNodeType.DocumentType:
Console.Write("<!DOCTYPE {0} [{1}]", reader.Name, reader.Value);
break;
case XmlNodeType.EntityReference:
Console.Write(reader.Name);
break;
case XmlNodeType.EndElement:
Console.Write("</{0}>", reader.Name);
//A known format of the XML input allows count to be used - TBD improve format reader
if (count == 3)
{
DPF(" Process Glitch and COUNT = 3");
ProcessGlitch = 1;
count = 0;
}
else
{
count = count + 1;
}
DPF("End Element found");
break;
}

if (EndXMLParse == 1)
{
break;//break out of XMLtextreader
}


//################################################
//Load the XML input data for 1 file to glitch fix
//################################################
if (ProcessGlitch == 1)
{
string szWavFile = Path.Combine(szPath, szFilename) + ".wav";//concatenated filename based on the path, filename and .wav

DPF("ENTERED GLITCH PROCESSING");
DPF("Count - {0}", count);
DPF("szFilename = {0}", szFilename);
DPF("szPath = {0}", szPath);
DPF("szStart = {0}", szStart);
DPF("szWidth = {0}", szWidth);
DPF("szWavFile assignment = {0}", szWavFile);

SfStatus result = SfStatus.Success;

//Add in a check that Dir has been set (if not set a default value)
if (null == szPath)
{
szPath = @"C:\";
DPF("NO DIRECTORY PARAMETER HAS BEEN SET AS AN INPUT PARAMETER. USE /Script:<path_to_script?Dir=<dir_path> WHEN CALLING SF");
}

DPF("{0} check the WAV File variable contents", szWavFile);

//#######################################################################
//Create the output file path and name to write the WAV output and log file
//#######################################################################
string szWavOutFile = szFilename;//output filename
DPF("szWavOutFile = {0}", szWavOutFile);
//string szOPDir = szPath + "\\dr\\";
string szOPDir = szPath + "\\dr\\";
if ( ! Directory.Exists(szOPDir))
{
Directory.CreateDirectory(szOPDir); // make sure that the directory exists...
}

//####################################################################
//check that the output file & log file doesn't already exist.
//If it does then add a number "_<ccFileExt>" to the name
//create the full path to the output directory
//####################################################################
szWavOutFile = Path.Combine(szOPDir, szWavOutFile) + ".wav";//adds extra output directory to each file
string szWavOutLogFile = Path.GetFileNameWithoutExtension(szWavOutFile);
for (Int64 ccFileExt = 1; ccFileExt < 16; ccFileExt++)
if (File.Exists(szWavOutFile))
{
szWavOutFile = (Path.Combine(szOPDir, (Path.GetFileNameWithoutExtension(szWavFile))) + ".wav");
szWavOutLogFile = Path.GetFileNameWithoutExtension(szWavOutFile);
}
else
{
result = SfStatus.Fail;
}
DPF("Output filename and directory debug {0}", szWavOutFile);
szWavOutLogFile = Path.Combine(szOPDir, szWavOutLogFile) + ".log";//adds extra output directory (\\dr\\ to each file
StreamWriter sw = new StreamWriter(szWavOutLogFile);
if ( ! File.Exists(szWavFile))
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error");
sw.WriteLine("Warning: Input File Does Not Exist with name : \n {0}", szWavFile);
sw.WriteLine("####################################################################################");
result = SfStatus.Fail;
}

//############################################################################################
//check that the start and width parameters are not 0 (if they are then generate an exception)
//############################################################################################
if (szStart == 0)
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: Glitch Removal Process Failed");
sw.WriteLine("fatal: An Error has occurred due to the start parameter having a value of 0");
sw.WriteLine("####################################################################################");
sw.WriteLine("szStart = {0}", szStart);
sw.WriteLine("szWidth = {0}", szWidth);
result = SfStatus.Fail;
sw.Close();//close the log file
}
else
{
sw.WriteLine("glitch start parameter has a valid value of {0}", szStart);
}

//###########################################################################################
//check that the glitch width parameter is valid
//###########################################################################################
if (szWidth == 0)
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: Glitch Removal Process Failed");
sw.WriteLine("fatal: An Error has occurred due to the Width parameter having a value of 0");
sw.WriteLine("####################################################################################");
result = SfStatus.Fail;
sw.Close();//close the log file
}
else
{
sw.WriteLine("Glitch width parameter has a valid value of {0}", szWidth);
}

//process the file using the audio restoration effect
DPF("szWavOutFile Output variable in to ProcessFile is {0}", szWavOutFile);
result = ProcessFile(app, szWavFile, szWavOutFile, szWavOutLogFile, sw, szStart, szWidth);
DPF("JUST COMPLETED GLITCH FIX PROCESS NOW PRINT RESULT");

DPF("~ - {0}", result);
if (result != SfStatus.Success)
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: Glitch Removal Process Failed");
sw.WriteLine("fatal: An Error has occurred whilst processing the audio file");
sw.WriteLine("####################################################################################");
sw.Close();//close the log file
}
else
{
sw.WriteLine(" ");
sw.WriteLine("####################################################################################");
sw.WriteLine("Glitch Removal Completed successfully");
sw.WriteLine("####################################################################################");
}

sw.Close();//close the log file

count = 0;//reset the count value
ProcessGlitch = 0;
DPF("Completed Processing of glitch. Reset ProcessGlitch to 0 to allow loading of the next set of XML parameters");
}


//#######################################
//END OF XML TEXT READER WHILE LOOP
//#######################################
}//while xmltextreader

//Close down the Whole process and quit out of soundforge
Thread.Sleep(1000);//Wait for 1 second
Process curr = Process.GetCurrentProcess();
Thread.Sleep(10000);//Wait for 10 seconds
DPF("Closing down Soundforge Csharp program run");
curr.CloseMainWindow();

} // Begin

//Function used to process the WAV input file and call the audio glitch removal function

public SfStatus ProcessFile(IScriptableApp app, string szWavFile, string szWavOutFile, string szWavOutLogFile, StreamWriter sw,int szStart, int szWidth)
{
SfStatus result = SfStatus.Success;

try
{
ISfFileHost fileIn = app.OpenFile(szWavFile, false, true);//not read-only, do not allow soundforge window

//Check that the file is not empty, if it is then set the status to fail
//Check that the file data length is 8 or more samples (minimum window size for glitch removal)
if ((null == fileIn) | (fileIn.Length <= 8)) {
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: ");
sw.WriteLine("fatal: Input file is Empty");
sw.WriteLine("####################################################################################");
return SfStatus.Fail;
}

//Restore the present file using the built in glitch removal function
Int64 ccLength = fileIn.Length;
Int64 ccGlitchPos = 0;
Int64 ccPosDiff = 1;//Sample Position Difference between glitches
Int64 ccEnd = 0;//End of Interpolation window sample value

ccEnd = szStart + szWidth;

//Set the audio selection region
SfAudioSelection AllAudio = new SfAudioSelection(szStart,ccEnd);//Select the whole audio waveform (0 = start, -1 = end)

DPF("Value of szStart = {0} ", szStart);
DPF("Value of ccEnd = {0} ", ccEnd);

//undertake glitch removal process
ccGlitchPos = szStart;//set the start glitch position

DPF("RUNNING FIRST PASS GLITCH REMOVAL");
sw.WriteLine("RUNNING FIRST PASS GLITCH REMOVAL");
//FIRST PASS GLITCH REMOVAL = loop until no more glitches are found
for (Int64 ccPos = szStart; ccPos < ccLength; ccPos += ccPosDiff)
{
if (result == SfStatus.Success)
{
SfAudioSelection GlitchReg = new SfAudioSelection(szStart, szWidth);//Create the Interpolation window
DPF("Value of szStart in First Pass = {0} ", szStart);
DPF("Value of ccEnd in first Pass= {0} ", ccEnd);
sw.WriteLine("Value of szStart = {0}", szStart);
sw.WriteLine("Value of ccEnd = {0}", ccEnd);
//select the audio selection from the start sample point of the glitch and the end point based on the glitch width + start
SfAudioSelection asel = new SfAudioSelection(szStart, ccEnd);
sw.WriteLine("SfAudioSelection completed correctly");//debug write message added

fileIn.Window.SetSelectionAndScroll(szStart, szWidth, DataWndScrollTo.Nearest);//added by TPA to move window
sw.WriteLine("fileIn.Window.SetSelectionAndScroll completed correctly");//debug write message added
app.DoMenuAndWait ("Tools: Repair Interpolate", true);
sw.WriteLine("app.DoMenuAndWait completed correctly");//debug write message added
//remove 1 from posDiff (this allows looping based on the default value of ccPosDiff
ccPosDiff = ccPosDiff - 1;
sw.WriteLine("ccPosDiff = ccPosDiff - 1 completed correctly");//debug write message added
if (ccPosDiff == 0)//Loop until no further glitches found
{
DPF("FIRST PASS PARAMETER BASED GLITCH REMOVAL COMPLETED");
break;
}

}
else
{
DPF("ERROR HAS OCCURRED DURING FIRST PASS LOOP. SFStatus is not .Success. Either File Loading Error or Glitch Detection Error");
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: ");
sw.WriteLine("Warning: Problem has occurred during FIRST PASS LOOP. SFStatus is not .Success. Either File Loading Error or Glitch Detection Error");
sw.WriteLine("####################################################################################");
result = SfStatus.Fail;
//fileIn.Close(CloseOptions.DiscardChanges);//close the input file
break;
}
}//end of for loop

DPF("COMPLETED FOR LOOP");
DPF("Value of szWavOutFile = {0}", szWavOutFile);
DPF("FileIn name = {0}", szWavFile);

//##############################################################################
//Write out the new audio file
//##############################################################################
ISfFileHost fileOut = fileIn.NewFile(new SfAudioSelection(0,-1));//select all of the current AudioSelection? Check this

//Select all of the audio from the present file, then overwrite the fileOut with this from fileIn
SfAudioSelection aselAllOut = new SfAudioSelection(0,-1);
fileOut.OverwriteAudio(0, 0, fileIn, aselAllOut);

if (null == fileOut)
{
DPF("Error - fileout is empty");
return SfStatus.Fail;
}

if (null == fileIn)
{
DPF("Error - fileIn is empty");
return SfStatus.Fail;
}

DPF("COMPLETED fileOut.OverwriteAudio");

//Added to find cause of Render problem
SfAudioSelection range = new SfAudioSelection(szStart, ccEnd);

//check that the FileOut length is valid
Int64 ccFOLength = fileOut.Length;
DPF("FILE OUT LENGTH = {0}", ccFOLength);

fileOut.RenderAs(szWavOutFile, fileOut.SaveFormat.Guid, 0, null, RenderOptions.RenderOnly);
DPF("COMPLETED fileOut.RenderAs");
result = fileOut.WaitForDoneOrCancel();

DPF("PROCESS FILE RESULT = {0}", result);

//#############################################################################
//Write out the audio file statistics and the audio restore info
//#############################################################################

//####################################################################
//Get the Statistics for the input and output files
//####################################################################
sw.WriteLine("####################################################################################");
sw.WriteLine("Input File Data Format & File Length");
sw.WriteLine(" Sample Rate, SampleType, Number of Channels = (" + fileIn.SampleRate + "," + fileIn.SampleType + "," + fileIn.Channels + ")");
sw.WriteLine("Input File Length (samples) = {0}", fileIn.Length);
sw.WriteLine("####################################################################################");
sw.WriteLine("Output File Data Format & File Length");
sw.WriteLine(" Sample Rate, SampleType, Number of Channels = (" + fileOut.SampleRate + "," + fileOut.SampleType + "," + fileOut.Channels + ")");
sw.WriteLine("Output File Length (samples) = {0}", fileOut.Length);
sw.WriteLine("####################################################################################");
DPF("Close File In and File Out");
fileIn.Close(CloseOptions.DiscardChanges);//close the input file
fileOut.Close(CloseOptions.DiscardChanges);//close the output file
}
catch(Exception e)
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error:");
sw.WriteLine("The following exception was caught:\n{0}", e);
sw.WriteLine("####################################################################################");
return SfStatus.Fail;
}

return result;
}

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));
DPF("Script {0} has completed", 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)); }
public static void DPF(string fmt, object o, object o2, object o3) { ForgeApp.OutputText(String.Format(fmt,o,o2,o3)); }
public static string GETARG(string k, string d) { string val = Script.Args.ValueOf(k); if (val == null || val.Length == 0) val = d; return val; }
public static int GETARG(string k, int d) { string s = Script.Args.ValueOf(k); if (s == null || s.Length == 0) return d; else return Script.Args.AsInt(k); }
public static bool GETARG(string k, bool d) { string s = Script.Args.ValueOf(k); if (s == null || s.Length == 0) return d; else return Script.Args.AsBool(k); }
} //EntryPoint

//*****************************************************************************
//* End Of File *
//*****************************************************************************


The XML input example looks like this


<?xml version="1.0" ?>
<root>
<Dir>c:\audio_src</Dir>
<file>test1</file>
<glitchstart>18</glitchstart>
<glitchwidth>18</glitchwidth>
<!--First Glitch Parameters-->
<Dir>c:\audio_src</Dir>
<file>test2</file>
<glitchstart>18</glitchstart>
<glitchwidth>18</glitchwidth>
<!--Second Glitch Parameters-->
<Dir>c:\audio_src</Dir>
<file>test3</file>
<glitchstart>20</glitchstart>
<glitchwidth>16</glitchwidth>
<!--Third Glitch Parameters-->
<Dir>c:\audio_src</Dir>
<file>test4</file>
<glitchstart>10</glitchstart>
<glitchwidth>12</glitchwidth>
<![CDATA[END]]>
</root>


Thanks

Tim

Message last edited on5/19/2008 12:28:58 AM bytimaddy.
Subject:RE: Hyperthreading problem with SF script
Reply by: _TJ
Date:5/21/2008 10:19:02 PM

There a several places in this script where you encounter an error, set status to failure and keep right on going trying to use the invalid arg/param/etc in subsequent calls.

This is a Fragment from your script, notice that even when szWidth is 0, you still call ProcessFile()


....
if (szWidth == 0)
{
sw.WriteLine("####################################################################################");
sw.WriteLine("Error: Glitch Removal Process Failed");
sw.WriteLine("fatal: An Error has occurred due to the Width parameter having a value of 0");
sw.WriteLine("####################################################################################");
result = SfStatus.Fail;
sw.Close();//close the log file
}
else
{
sw.WriteLine("Glitch width parameter has a valid value of {0}", szWidth);
}

//process the file using the audio restoration effect
DPF("szWavOutFile Output variable in to ProcessFile is {0}", szWavOutFile);
result = ProcessFile(app, szWavFile, szWavOutFile, szWavOutLogFile, sw, szStart, szWidth);
...


When your script encounters an error, you don't necessarily need to break out of the loop, but you do need to skip the call to ProcessFile(), and probably other calls as well.

tj


Go Back