Subject:Save Regions out with Filenames from list
Posted by: ZakB
Date:9/29/2005 8:38:56 AM
Hello there- I'm an audio director for a game development house, and one of the biggest tasks we have is to cut up voiceover audio into thousands of small files. The scripting power of Sound Forge 8 looks like it might be a solution to this problem. Too bad I'm not much of a coder, and I'm having trouble figuring out where to start. Here's what I'd like to do: 1) I'll mark a large file with a set of sequental region names from start to finish and save it out. So, I'll have voiceover.wav have regions called Snd01, Snd02, etc regions. 2) Read in a textfile with a sequential list of filenames, say Filename01.wav, Filename02.wav etc 3) Save out the regions in the the large master file using the filenames in the textfile. So, region Snd01 would be saved as Filename01.wav, region Snd02 would be saved out as Filename02.wav, etc. This kind of functionality would be wildy appreciated in the game production community- and if anyone can help I'll spread the word and the appreciation :) Thanks!- Zak Message last edited on9/29/2005 8:39:10 AM byZakB. |
Subject:RE: Save Regions out with Filenames from list
Reply by: _TJ
Date:9/30/2005 1:02:58 AM
Have a look at the thread called "Script: Create new files from each marker" by Sound Samurai It doesn't make any use of a text file to name the files, but I have to wonder if it isn't easier to just use the marker/region names as the filenames in the first place, which is what this script does. tj |
Subject:RE: Save Regions out with Filenames from list
Reply by: _TJ
Date:9/30/2005 1:32:02 AM
The workflow you are describing strikes me as somewhat error prone, but in case you want to go with the use a text file to control filenames, that's pretty easy to do. Lets assume that the file of filenames is structured so that each line is a filename, and that we won't tolerate blank lines or illegal characters. One of the hard parts about parsing is tolerating minor variations that don't appear serious to the people creating the file, but are unexpected to the parsing code. If we just assume that the text file is perfect, then parsing it is really easy. (there are actually several ways to do this - I'll just show you one). using System; using System.IO; using System.Windows.Forms; using SoundForge; public class EntryPoint { public string Begin(IScriptableApp app) { string sNameListFileName = @"c:\filenamelist.txt"; // get the currently open file - we will save regions from it. ISfFileHost file = app.CurrentFile; 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."; // open the file containing the list of filenames StreamReader namefile = new StreamReader(sNameListFileName); // we will save our files in the same format as the current file. ISfRenderer render = file.SaveFormat; SfAudioMarkerList markers = file.Markers; // loop through markes and regions in the current file. foreach (SfAudioMarker mk in file.Markers) { // process the regions, ignore the markers. if (mk.IsRegion) { // get the next filename from our namelist string sFilename = namefile.ReadLine().Trim(); SfAudioSelection range = new SfAudioSelection(mk.Start, mk.Length); file.RenderAs(sFilename, render.Name, "Default Template", range, RenderOptions.RenderOnly); } } 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)); } } //EntryPoint |
Subject:RE: Save Regions out with Filenames from list
Reply by: ZakB
Date:9/30/2005 9:27:20 AM
Thanks SonyTJ for the fast reply, it works like a charm! Zak |
Subject:RE: Save Regions out with Filenames from list
Reply by: ZakB
Date:9/30/2005 12:06:01 PM
So I've been trying to adapt this script to do the reverse: open files from the list in filenames.txt, apply a plugin chain to it, and then save the file. There are some good examples on this site on how to go about it, but I'm such a clueless coder that I can't get anything I write to compile. Heh, help a possibility? Thanks! Zak |
Subject:RE: Save Regions out with Filenames from list
Reply by: _TJ
Date:10/1/2005 12:27:19 PM
Here's what the basic structure of a loop opening files from a list of files might look like. string sNameListFileName = @"c:\filenamelist.txt"; StreamReader namefile = new StreamReader(sNameListFileName); // process all names from the namefile for (;;) { string sFilename = namefile.ReadLine().Trim(); // quit if filename string is empty if (sFilename == null || sFilename == "") break; // open the file in Sound Forge, quit if the name is invalid. ISfFileHost file = app.OpenFile(sFilename, false, false); if (null == file) break; // do your processing on the file here. } |
Subject:RE: Save Regions out with Filenames from list
Reply by: _TJ
Date:10/1/2005 12:32:35 PM
A piece of advice - If you get stuck trying to write some code - POST THE CODE. I'm sure with some code to look at, there are several people here who would be willing to help you. You'll get a lot less help with an open request to guess what you need and write the code for you, than if you just need someone to point out why the code you are trying won't compile. Also, you learn more the second way. To make code look like code when you post it. You should surround it with a <pre> </pre> tag pair. tj |
Subject:RE: Save Regions out with Filenames from list
Reply by: ZakB
Date:10/5/2005 10:57:55 AM
Hey there TJ, thanks for the help and advice. So, the script works well up until I try processing it with a app.DoMenu("“View.PlugInChainer”",true); command. Sound Forge says "Sound Forge Error 0x8004E00A The item was not found. while calling SoundForge.SfStatus DoMenu(System.String, Boolean) --------message---------- Exception from HRESULT: 0x8004E00A. --------Stack Trace---------- at SoundForge.IScriptableApp.DoMenu(String pszCmdName, Boolean fUseDefaultArguments) at EntryPoint.Begin(IScriptableApp app) at EntryPoint.FromSoundForge(IScriptableApp app) Anyway, here's my script so far, it opens the files and is almost there... using System; using System.IO; using System.Windows.Forms; using SoundForge; public class EntryPoint { public string Begin(IScriptableApp app) { string sNameListFileName = @"c:\filenamelist.txt"; // get the currently open file - we will save regions from it. ISfFileHost file = app.CurrentFile; // open the file containing the list of filenames StreamReader namefile = new StreamReader(sNameListFileName); // we will save our files in the same format as the current file. //ISfRenderer render = file.SaveFormat; // process all names from the namefile for (;;) { string sFilename = namefile.ReadLine().Trim(); // quit if filename string is empty if (sFilename == null || sFilename == "") break; // open the file in Sound Forge, quit if the name is invalid. ISfFileHost nfile = app.OpenFile(sFilename, false, false); if (null == nfile) break; // do your processing on the file here. MessageBox.Show("About to process"); app.DoMenu("“View.PlugInChainer”",true); } 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)); } } //EntryPoint |
Subject:RE: Save Regions out with Filenames from list
Reply by: jetdv
Date:10/5/2005 12:32:32 PM
"“View.PlugInChainer”" It looks like you have an extra set of single quotes in there. How about changing the above to: "View.PlugInChainer" |
Subject:RE: Save Regions out with Filenames from list
Reply by: ZakB
Date:10/5/2005 2:10:22 PM
Heh, yep jetdv, you're right, too many quotes. Now it works, I guess my problem is that I still can't find a way to call up a plugin chainer preset and execute it. I'll keep looking around. Thanks! Zak |
Subject:RE: Save Regions out with Filenames from list
Reply by: ZakB
Date:10/5/2005 2:53:28 PM
OK, I'm getting much much closer... This is where my weakness at programming comes in. I've got it set up where the script opens the files, asks you to choose a PlugIn Chainer preset, and applies the preset. However, the loop is set up where the script asks you to choose a PlugIn Chainer preset before every file, and then applies the preset to all open files, so the first files get the effect applied too many times. I'm looking for a way for the script to open all the files first, and then choose a PlugIn Chainer preset, and then applies the preset to all open files. Heh, told you I was a bad programmer ;) Here's the script- using System; using System.IO; using System.Windows.Forms; using SoundForge; public class EntryPoint { public string Begin(IScriptableApp app) { string sNameListFileName = @"c:\filenamelist.txt"; // get the currently open file - we will save regions from it. ISfFileHost file = app.CurrentFile; // open the file containing the list of filenames StreamReader namefile = new StreamReader(sNameListFileName); // we will save our files in the same format as the current file. //ISfRenderer render = file.SaveFormat; // process all names from the namefile for (;;) { string sFilename = namefile.ReadLine().Trim(); // quit if filename string is empty if (sFilename == null || sFilename == "") break; // open the file in Sound Forge, quit if the name is invalid. ISfFileHost nfile = app.OpenFile(sFilename, false, false); if (null == nfile) break; // do your processing on the file here. // MessageBox.Show("About to process"); string szPlug = "View.PlugInChainer"; ISfGenericPreset preset = app.DoEffect(szPlug, 0, EffectOptions.ReturnPreset | EffectOptions.DialogOnly); if (null != preset) { DPF("preset is '" + szPlug + "," + preset.Name + "' size=" + preset.Size); foreach (ISfFileHost wfile in app.Files) { SfAudioSelection asel = wfile.Window.EditRegion; DPF(" edit region is " + asel.ToString()); try { wfile.DoEffect(null, preset, asel, EffectOptions.EffectOnly); } catch (Exception e) { DPF("failure or cancel: " + e.ToString()); } DPF("File.DoEffect(" + szPlug + ", " + preset.Name + " started."); } DPF("Waiting for all to finish"); SfStatus result = app.WaitForDoneOrCancel(); DPF("~ {0}", result.ToString()); } } 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)); } } //EntryPoint Message last edited on10/5/2005 2:54:04 PM byZakB. |
Subject:RE: Save Regions out with Filenames from list
Reply by: _TJ
Date:10/5/2005 11:46:50 PM
You just need to break it into two loops // open all of the files. for (;;) { string sFilename = namefile.ReadLine().Trim(); // quit if filename string is empty if (sFilename == null || sFilename == "") break; // open the file in Sound Forge, quit if the name is invalid. ISfFileHost nfile = app.OpenFile(sFilename, false, false); if (null == nfile) break; } // <---------------------------- The change is here!! // choose a chainer preset string szPlug = "View.PlugInChainer"; ISfGenericPreset preset = app.DoEffect(szPlug, 0, EffectOptions.ReturnPreset | EffectOptions.DialogOnly); if (null != preset) { DPF("preset is '" + szPlug + "," + preset.Name + "' size=" + preset.Size); foreach (ISfFileHost wfile in app.Files) { SfAudioSelection asel = wfile.Window.EditRegion; DPF(" edit region is " + asel.ToString()); try { wfile.DoEffect(null, preset, asel, EffectOptions.EffectOnly); } catch (Exception e) { DPF("failure or cancel: " + e.ToString()); } DPF("File.DoEffect(" + szPlug + ", " + preset.Name + " started."); } DPF("Waiting for all to finish"); SfStatus result = app.WaitForDoneOrCancel(); DPF("~ {0}", result.ToString()); } |
Subject:RE: Save Regions out with Filenames from list
Reply by: ZakB
Date:10/6/2005 8:04:32 AM
Hmm, this looks like it should work, and it compiles, but I get an error running this script, it quits out before it gets to the plugin chainer section with the error: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object. at EntryPoint.Begin(IScriptableApp app) at EntryPoint.FromSoundForge(IScriptableApp app) --- End of inner exception stack trace --- at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess) at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean verifyAccess) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at SoundForge.ScriptManager.Run(Assembly asm, String className, String methodName) at SoundForge.CodeDomScriptManager.Run(Assembly assy) at SoundForge.ScriptHost.RunScript(String szFile, String szSourceText, EngineType eType, Boolean fCompileOnly, Boolean fDebug) Here's the script as I have it: using System; using System.IO; using System.Windows.Forms; using SoundForge; public class EntryPoint { public string Begin(IScriptableApp app) { string sNameListFileName = @"c:\filenamelist.txt"; // get the currently open file - we will save regions from it. ISfFileHost file = app.CurrentFile; // open the file containing the list of filenames StreamReader namefile = new StreamReader(sNameListFileName); // we will save our files in the same format as the current file. //ISfRenderer render = file.SaveFormat; // open all of the files. for (;;) { string sFilename = namefile.ReadLine().Trim(); // quit if filename string is empty if (sFilename == null || sFilename == "") break; // open the file in Sound Forge, quit if the name is invalid. ISfFileHost nfile = app.OpenFile(sFilename, false, false); if (null == nfile) break; } // <---------------------------- The change is here!! // choose a chainer preset string szPlug = "View.PlugInChainer"; ISfGenericPreset preset = app.DoEffect(szPlug, 0, EffectOptions.ReturnPreset | EffectOptions.DialogOnly); if (null != preset) { DPF("preset is '" + szPlug + "," + preset.Name + "' size=" + preset.Size); foreach (ISfFileHost wfile in app.Files) { SfAudioSelection asel = wfile.Window.EditRegion; DPF(" edit region is " + asel.ToString()); try { wfile.DoEffect(null, preset, asel, EffectOptions.EffectOnly); } catch (Exception e) { DPF("failure or cancel: " + e.ToString()); } DPF("File.DoEffect(" + szPlug + ", " + preset.Name + " started."); } DPF("Waiting for all to finish"); SfStatus result = app.WaitForDoneOrCancel(); DPF("~ {0}", result.ToString()); } 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)); } } //EntryPoint |
Subject:RE: Save Regions out with Filenames from list
Reply by: _TJ
Date:10/6/2005 11:38:58 AM
ok. It turns out that the code I gave you for getting filenames from a file has a bug in it. When it gets to the end of the file the expression namefile.ReadLine() evaluates to null which then fails when you try to Trim();. The trim is there so that we can tolerate lines in the file that have leading or trailing spaces, so you could just get rid of it. Otherwise, you need to break that expression up and do the null test before tring to Trim(). // open all of the files. for (;;) { string sFilename = namefile.ReadLine(); // quit when we get to the end of the file. if (sFilename == null) break; sFilename = sFilename.Trim(); if (sFilename != "") { // open the file in Sound Forge, quit if the name is invalid. ISfFileHost nfile = app.OpenFile(sFilename, false, false); if (null == nfile) break; } } Message last edited on10/6/2005 11:43:50 AM by_TJ. |