I managed to cobble together a script that will save regions to individual mp3 files using RenderAs. My problem is how to determine when all the regions have been rendered and rendering is complete.. Does anyone know how to do that using c#? Thanks.
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.
@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.
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.
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
@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
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
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