Я обрабатываю в программе Sound Forge 9 записи лекций. Лекции диктовались под запись, поэтому между словами и фразами значительные паузы. Моя цель - удалить паузы. При этом лекция становится в два раза короче. Эти паузы я отслеживаю по громкости звука, но часто в паузу попадают непродолжительные шумы, по громкости сопоставимые с голосом, что делает невозможным удаление паузы целиком. К счастью шумы, которые попадают в паузы имеют продолжительность не более полсекунды, а одно слово лектор произносит минимум за полсекунды. Вообщем, в итоге у меня все сводится к тому, что надо сохранить все области (отмеченные части звукового файла) в один файл. В Sound Forge есть файл скрипта, который сохраняет каждую область в отдельный файл. Вот его содержание:
Код:
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 void Begin(IScriptableApp app) {
//MODIFY HERE-----------------------------------------------
string szType = ".pca"; //choose any valid extension: .avi .wav .w64 .mpg .mp3 .wma .mov .rm .aif .ogg .raw .au .dig .ivc .vox .pca
object vPreset = ""; //put the name of the template between the quotes, or leave blank to pop the Template chooser.
string szDir = @"c:\Media\Rip"; //change the target path here
ISfFileHost file = app.CurrentFile;
if (null == file)
{
app.SetStatusText("Open a file containing regions before running this script. Script stopped.");
return;
}
//make sure the directory exists
Directory.CreateDirectory(szDir);
ISfRenderer rend = null;
if (szType.StartsWith("."))
rend = app.FindRenderer(null, szType);
else
rend = app.FindRenderer(szType, null);
if (null == rend)
{
app.SetStatusText("Renderer not found. Script stopped.");
DPF("renderer for {0} not found.", szType);
return;
}
// 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)
{
app.SetStatusText("Template not found. Script stopped.");
return;
}
string szBase = file.Window.Title;
foreach (SfAudioMarker mk in file.Markers)
{
if (mk.Length <= 0)
continue;
string szName = String.Format("{0:d2}-{1}-({2}).{3}", mk.Ident, szBase, mk.Name, rend.Extension);
szName = SfHelpers.CleanForFilename(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.RenderOnly);
}
SfStatus status = app.WaitForDoneOrCancel();
DPF("Done -{0}", status);
}
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 fmt, params object[] args) { ForgeApp.OutputText(String.Format(fmt, args)); }
} //EntryPoint
А мне нужно сохранить все области в один файл. Скорее всего, переделать этот скрипт под мою задачу совсем просто, но я раньше вообще не писал на C#. Главное, конечно, делается в цикле
Код:
foreach (SfAudioMarker mk in file.Markers)
{
if (mk.Length <= 0)
continue;
string szName = String.Format("{0:d2}-{1}-({2}).{3}", mk.Ident, szBase, mk.Name, rend.Extension);
szName = SfHelpers.CleanForFilename(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.RenderOnly);
}