Comments

SP. wrote on 10/7/2024, 2:57 AM

@Unsounded The script should finish itself after every step has been completed. Or do you mean something different?

Unsounded wrote on 10/7/2024, 8:51 AM

Thanks for the reply. What I mean is that the actual rendering takes longer. I put a msgbox at the end of my script but it appears before all the files have been created. I want to be able to monitor the rending process and take action when all the files have been rendered.

SP. wrote on 10/7/2024, 9:22 AM

@Unsounded Did you pass the RenderOptions.WaitForDoneOrCancel parameter as the last parameter of RenderAs? Otherwise the script will continue with the next step before the rendering has finished.

Unsounded wrote on 10/7/2024, 3:43 PM

Thanks for the suggestion, I was using

file.RenderAs(szFullName, rend.Guid, template, range, RenderOptions.RenderOnly);

I changed this to:

file.RenderAs(szFullName, rend.Guid, template, range, RenderOptions.WaitForDoneOrCancel );

But I still see my message at the end of the script before all the files have rendered. As an experiment I replaced the message box with:

app.DoMenuAndWait("File.Close", false);

The file closed before the rendering was done. The rendering completed itself and then Sound Forge crashed. Do you have any other suggestion? Thank again.

SP. wrote on 10/8/2024, 12:09 AM

@Unsounded Show me your script.

Unsounded wrote on 10/8/2024, 4:58 AM

Here it is as it stands now. I'm saving the number of files to render to a text file and then using an autohotkey script to monitor the folder. It is working but very clunky. I really find c# tough going. I appreciate any pointers you can offer.

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

//Run with a file that contains regions
//Iterates through the regions, renders to PCA and saves the rendered file to c:\media\rip
//Scan the file for MODIFY HERE to see how to quickly customize for your own use

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

   //start MODIFY HERE-----------------------------------------------
   string szType  = GETARG("type", ".mp3"); //choose any valid extension: .avi  .wav  .w64 .mpg .mp3 .wma .mov .rm .aif .ogg .raw .au .dig .ivc .vox .pca
   object vPreset = GETARG("preset", "Vocab For Web"); //put the name of the template between the quotes, or leave blank to pop the Template chooser. 
   string szDir   = GETARG("dir", ""); //hardcode a target path here

   // GETARG is a function that defines the default script settings. You can use the Script Args field to over-ride
   // the values within GETARG().
   // Example: To over-ride GETARG(Key, valueA), type Key=valueB in the Script Args field.
   //          Use an ampersand (&) to separate different Script Args: KeyOne=valueB&KeyTwo=valueC

   //Example Script Args: type=.wav&dir=f:\RegionFiles

   //end MODIFY HERE -----------------------------------
	
	ISfFileHost file = app.CurrentFile;
	ISfDataWnd wnd = app.ActiveWindow;

   if (null == file)
      return "Open a file containing regions before running this script. Script stopped.";
   if (null == file.Markers || file.Markers.Count <= 0)
      return "The file does not have any markers.";

	// Save file first
	app.DoMenuAndWait("File.Save", false);

	//bool showMsg = true;
	if (!File.Exists(@"C:\Temp\#loc.txt"))
	{
		  bool showMsg = true;
			if (szDir == null || szDir.Length <= 0)
			{
				szDir = PromptForPath(@"L:\Text to speech\#auto");
				showMsg = false;
			}
			if (szDir == null || szDir.Length <= 0 || showMsg)
			{
				MessageBox.Show(String.Format("No output directory - operation cancelled!", szDir), "Oops!", MessageBoxButtons.OK, MessageBoxIcon.Information);
				return "No output directory - operation cancelled!";	
			}		
	}
	else
	{
		// Open regionPath.txt
		StreamReader current = new StreamReader(@"C:\Temp\#loc.txt");

		// read last used path
		szDir = current.ReadLine().Trim();

		current.Close();
	}
	
   //make sure the directory exists
   if(!Path.IsPathRooted(szDir))
   {
      string szBase2 = Path.GetDirectoryName(file.Filename);
      szDir = Path.Combine(szBase2, szDir);
   }

   Directory.CreateDirectory(szDir);

   ISfRenderer rend = null;
   if (szType.StartsWith("."))
       rend = app.FindRenderer(null, szType);
   else 
       rend = app.FindRenderer(szType, null);

   if (null == rend)
   return String.Format("renderer for {0} not found.", szType);

   // if the preset parses as a valid integer, then use it as such, otherwise assume it's a string.
   try {
       int iPreset = int.Parse((string)vPreset);
       vPreset = iPreset;
   } catch (FormatException) {}

   ISfGenericPreset template = null;
   if ((string)vPreset != "")
      template = rend.GetTemplate(vPreset);
   else   
      template = rend.ChooseTemplate((IntPtr)null, vPreset);
   if (null == template)
      return "Template not found. Script stopped.";
	   
	string szBase = file.Window.Title;

	//showMsg = true;
	foreach (SfAudioMarker mk in file.Markers)
	{
		if (mk.IsRegion)
		{
			string szName = String.Format("{0:}{2}.{3}", "", szBase, mk.Name, rend.Extension);
			szName = CleanFilename(szName,app.CurrentFile.Filename);
			
			if (szName != "!")
			{			
				DPF("Queueing: '{0}'", szName);

				string szFullName = Path.Combine(szDir, szName);
				if (File.Exists(szFullName))
				File.Delete(szFullName);

				SfAudioSelection  range = new SfAudioSelection(mk.Start, mk.Length);
				file.RenderAs(szFullName, rend.Guid, template, range, RenderOptions.WaitForDoneOrCancel );
				DPF("Path: '{0}'", szFullName);
			}	
		}
   }   

  // if(showMsg)
  // MessageBox.Show(String.Format("Files are saving to: {0}", szDir), "Status", MessageBoxButtons.OK, MessageBoxIcon.Information);
 
 	//==================================================
	//Count regions and save this number to a file
	
	long countRegions = 0;
	
	foreach (SfAudioMarker mk in file.Markers)
	{
		if (mk.IsRegion)
		countRegions++;
	}
	
	System.IO.File.Delete(@"C:\Temp\#reg.txt");
	TextWriter reg = new StreamWriter(@"C:\Temp\#reg.txt");
	reg.WriteLine(szDir);
	reg.WriteLine(countRegions);
	reg.Close();
	
	//==================================================
 
   return null;
}

public string CleanFilename(string szName,string whem)
{
   szName = szName.Replace("!", "");    
   szName = szName.Replace("..", ".");  
   szName = szName.Replace("?", "");    
   szName = szName.Replace(":", " - "); 
   szName = szName.Replace('\\', '_'); 
   szName = szName.Replace('/', '_'); 
  
   foreach (char ch in System.IO.Path.GetInvalidPathChars())
   {
      szName = szName.Replace(ch, '_'); 
   }
   
   whem = whem.Replace(".mp3","");
   
   //Is it a whem wordlist?
   if (whem.Contains("Wordlists"))
   { 
   	if (whem.Contains("Ryan"))
		szName = szName.Replace(".mp3","1.mp3");
		if (whem.Contains("Aria"))
		szName = szName.Replace(".mp3","2.mp3");
		if (whem.Contains("Maisie"))
		szName = szName.Replace(".mp3","3.mp3");

		szName = szName.Replace(" ","_");
		szName = szName.ToLower();
   }
   
   return szName;
}

public string PromptForPath(string szDir) {

   FolderBrowserDialog dlg = new FolderBrowserDialog();
   
   dlg.Description = szDir;        
   //if (null != szDir && "" != szDir)
      dlg.SelectedPath = szDir;
   dlg.ShowNewFolderButton = true;
   DialogResult res = dlg.ShowDialog();         
   if (res == DialogResult.OK)
      return dlg.SelectedPath;
   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;
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

 

SP. wrote on 10/11/2024, 1:53 PM

@Unsounded Hmm, besides the unusual formatting (is this a problem of the code tag in this forum?) of your code the only odd thing I currently see is the line

string szName = String.Format("{0:}{2}.{3}", "", szBase, mk.Name, rend.Extension);

After the colon (in the first placeholder) should be followed by formatString (for example yyyy, if you only want the four digit year of a date value). But yours is simply empty and the {0:} gets then replaced by "", so it's not even necessary. I could simply look like

string szName = String.Format("{2}.{3}", "", szBase, mk.Name, rend.Extension);

I don't think that should have any influence on the way RenderAs works. But I don't know if the Sound Forge Compiler is any way unique and may have a problem with that.

 

Here I try a better formatting. I'm currently on my phone so this might not be perfect:

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

//Run with a file that contains regions
//Iterates through the regions, renders to PCA and saves the rendered file to c:\media\rip
//Scan the file for MODIFY HERE to see how to quickly customize for your own use

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

   //start MODIFY HERE-----------------------------------------------
   string szType  = GETARG("type", ".mp3"); //choose any valid extension: .avi  .wav  .w64 .mpg .mp3 .wma .mov .rm .aif .ogg .raw .au .dig .ivc .vox .pca
   object vPreset = GETARG("preset", "Vocab For Web"); //put the name of the template between the quotes, or leave blank to pop the Template chooser. 
   string szDir   = GETARG("dir", ""); //hardcode a target path here

   // GETARG is a function that defines the default script settings. You can use the Script Args field to over-ride
   // the values within GETARG().
   // Example: To over-ride GETARG(Key, valueA), type Key=valueB in the Script Args field.
   //          Use an ampersand (&) to separate different Script Args: KeyOne=valueB&KeyTwo=valueC

   //Example Script Args: type=.wav&dir=f:\RegionFiles

   //end MODIFY HERE -----------------------------------
    
    ISfFileHost file = app.CurrentFile;
    ISfDataWnd wnd = app.ActiveWindow;

   if (null == file)
      return "Open a file containing regions before running this script. Script stopped.";
   if (null == file.Markers || file.Markers.Count <= 0)
      return "The file does not have any markers.";

    // Save file first
    app.DoMenuAndWait("File.Save", false);

    //bool showMsg = true;
    if (!File.Exists(@"C:\Temp\#loc.txt"))
    {
          bool showMsg = true;
            if (szDir == null || szDir.Length <= 0)
            {
                szDir = PromptForPath(@"L:\Text to speech\#auto");
                showMsg = false;
            }
            if (szDir == null || szDir.Length <= 0 || showMsg)
            {
                MessageBox.Show(String.Format("No output directory - operation cancelled!", szDir), "Oops!", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return "No output directory - operation cancelled!";    
            }        
    }
    else
    {
        // Open regionPath.txt
        StreamReader current = new StreamReader(@"C:\Temp\#loc.txt");

        // read last used path
        szDir = current.ReadLine().Trim();

        current.Close();
    }
    
   //make sure the directory exists
   if(!Path.IsPathRooted(szDir))
   {
      string szBase2 = Path.GetDirectoryName(file.Filename);
      szDir = Path.Combine(szBase2, szDir);
   }

   Directory.CreateDirectory(szDir);

   ISfRenderer rend = null;
   if (szType.StartsWith("."))
       rend = app.FindRenderer(null, szType);
   else 
       rend = app.FindRenderer(szType, null);

   if (null == rend)
   return String.Format("renderer for {0} not found.", szType);

   // if the preset parses as a valid integer, then use it as such, otherwise assume it's a string.
   try {
       int iPreset = int.Parse((string)vPreset);
       vPreset = iPreset;
   } catch (FormatException) {}

   ISfGenericPreset template = null;
   if ((string)vPreset != "")
      template = rend.GetTemplate(vPreset);
   else   
      template = rend.ChooseTemplate((IntPtr)null, vPreset);
   if (null == template)
      return "Template not found. Script stopped.";
       
    string szBase = file.Window.Title;

    //showMsg = true;
    foreach (SfAudioMarker mk in file.Markers)
    {
        if (mk.IsRegion)
        {
            string szName = String.Format("{2}.{3}", "", szBase, mk.Name, rend.Extension);
            szName = CleanFilename(szName,app.CurrentFile.Filename);
            
            if (szName != "!")
            {            
                DPF("Queueing: '{0}'", szName);

                string szFullName = Path.Combine(szDir, szName);
                if (File.Exists(szFullName))
                File.Delete(szFullName);

                SfAudioSelection  range = new SfAudioSelection(mk.Start, mk.Length);
                file.RenderAs(szFullName, rend.Guid, template, range, RenderOptions.WaitForDoneOrCancel );
                DPF("Path: '{0}'", szFullName);
            }    
        }
   }   

  // if(showMsg)
  // MessageBox.Show(String.Format("Files are saving to: {0}", szDir), "Status", MessageBoxButtons.OK, MessageBoxIcon.Information);
 
     //==================================================
    //Count regions and save this number to a file
    
    long countRegions = 0;
    
    foreach (SfAudioMarker mk in file.Markers)
    {
        if (mk.IsRegion)
        countRegions++;
    }
    
    System.IO.File.Delete(@"C:\Temp\#reg.txt");
    TextWriter reg = new StreamWriter(@"C:\Temp\#reg.txt");
    reg.WriteLine(szDir);
    reg.WriteLine(countRegions);
    reg.Close();
    
    //==================================================
 
   return null;
}

public string CleanFilename(string szName,string whem)
{
   szName = szName.Replace("!", "");    
   szName = szName.Replace("..", ".");  
   szName = szName.Replace("?", "");    
   szName = szName.Replace(":", " - "); 
   szName = szName.Replace('\\', '_'); 
   szName = szName.Replace('/', '_'); 
  
   foreach (char ch in System.IO.Path.GetInvalidPathChars())
   {
      szName = szName.Replace(ch, '_'); 
   }
   
   whem = whem.Replace(".mp3","");
   
   //Is it a whem wordlist?
   if (whem.Contains("Wordlists"))
   { 
       if (whem.Contains("Ryan"))
        szName = szName.Replace(".mp3","1.mp3");
        if (whem.Contains("Aria"))
        szName = szName.Replace(".mp3","2.mp3");
        if (whem.Contains("Maisie"))
        szName = szName.Replace(".mp3","3.mp3");

        szName = szName.Replace(" ","_");
        szName = szName.ToLower();
   }
   
   return szName;
}

public string PromptForPath(string szDir) {

   FolderBrowserDialog dlg = new FolderBrowserDialog();
   
   dlg.Description = szDir;        
   //if (null != szDir && "" != szDir)
      dlg.SelectedPath = szDir;
   dlg.ShowNewFolderButton = true;
   DialogResult res = dlg.ShowDialog();         
   if (res == DialogResult.OK)
      return dlg.SelectedPath;
   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;
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