Community Forums Archive

Go Back

Subject:Statistics:RMS script
Posted by: David Thiel
Date:5/29/2006 2:31:03 PM

Thanks to a example script posted by sonyDJ I was able to write a script that writes a text file with the length, RMS amplitude and file name of each wave file in a directory. It has been a great help with normalizing the problem files of a speech cutup where I have 400 small speech files.
I'm sure it could be 'cleaner' but it is my first C# program and I've got to get back to my real project.
After reviewing the posted message I just noticed that it only works for mono files. It could be easily fixed for stereo if you care.
Here it is:
using System;
using System.IO;
using System.Windows.Forms;
using SoundForge;

public class EntryPoint {

public void Begin(IScriptableApp app) {

string strFolder = SfHelpers.ChooseDirectory("Choose a folder to process files from", @"C:\");
using (StreamWriter sw = new StreamWriter("SFileStats.txt"))
foreach (string strFilename in Directory.GetFiles(strFolder, "*.wav"))
{
SfStatus status = ProcessFile(app, strFilename,sw);
if (status != SfStatus.Success)
{
DPF("{0} : {1}", strFilename, status.ToString());

// quit if processing or save failed.
break;
} //foreach
} //Begin
} //Entrypoint

public bool bEnableProcessingLog = false;

public SfStatus ProcessFile(IScriptableApp app, string strFilename, StreamWriter sw)
{
string result;
string bFormatted;
if (bEnableProcessingLog)
DPF("processing {0}", strFilename);

ISfFileHost file = app.OpenFile(strFilename, false, true);
if (null == file)
return SfStatus.Fail;

result = Path.GetFileName(strFilename);
DPF("processing {0}", result);

// TODO: do your file processing here.

//ISfFileHost file = app.CurrentFile;

file.UpdateStatistics(null);
file.WaitForDoneOrCancel();

if (file.StatisticsAreUpToDate)
{
//DPF("'{0}' {1}", file.Filename, file.DataFormat.ToString());
SfAudioStatistics[] stat = new SfAudioStatistics[file.Channels];
for (uint ii = 0; ii < file.Channels; ++ii)
{
stat[ii] = file.GetStatistics(ii);
}

ISfPositionFormatter pos = file.Formatter;

if (file.Channels == 1)
{

//DPF("{0,36} ", pos.Format(stat[0].Length));
//DPF("RMSLevel {0,20} dB", Math.Round(SfHelpers.RatioTodB(stat[0].RMSLevel),1));

sw.Write(Math.Round(SfHelpers.RatioTodB(stat[0].RMSLevel),1));
sw.Write("\t");
bFormatted = pos.Format(stat[0].Length);
bFormatted = bFormatted.Remove(0,6);
sw.Write(bFormatted);
sw.Write("\t");
sw.WriteLine(Path.GetFileName(strFilename));
}
else if (file.Channels == 2)
{
Int64 ccPeak0 = stat[0].MaxValueLocation;
double dPeak0 = stat[0].MaxValue;
if (Math.Abs(stat[0].MinValue) > dPeak0)
{
dPeak0 = Math.Abs(stat[0].MinValue);
ccPeak0 = stat[0].MinValueLocation;
} //end if(Math.Abs(stat[0]
Int64 ccPeak1 = stat[1].MaxValueLocation;
double dPeak1 = stat[1].MaxValue;
if (Math.Abs(stat[1].MinValue) > dPeak1)
{
dPeak1 = Math.Abs(stat[1].MinValue);
ccPeak1 = stat[1].MinValueLocation;
} //end if(Math.Abs[1]....

DPF("-----Parameter------ {0,20} {1,20} ", "----Left----", "----Right----");
// DPF("Start {0,20} {1,20} ", pos.Format(stat[0].Start) , pos.Format(stat[1].Start) );
DPF("Length {0,20} {1,20} ", pos.Format(stat[0].Length) , pos.Format(stat[1].Length) );
DPF("Average {0,20} {1,20} ", stat[0].Average, stat[1].Average);
DPF("RMSLevel {0,20} dB {1,20} dB", SfHelpers.RatioTodB(stat[0].RMSLevel), SfHelpers.RatioTodB(stat[1].RMSLevel));
}
}
else
{
DPF("Statistics are NOT up to date");
}



// wait for processing to complete, and if it succeeds, save the file
SfStatus status = file.WaitForDoneOrCancel();
if (status == SfStatus.Success)
{
file.Save(SaveOptions.PromptIfNoFilename);
status = file.WaitForDoneOrCancel();
}

file.Close(CloseOptions.DiscardChanges);
return 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 with status", 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 on5/29/2006 2:32:55 PM byDavid Thiel.
Subject:RE: Statistics:RMS script
Reply by: _TJ
Date:5/31/2006 3:58:15 PM

Thank you.
tj

Subject:RE: Statistics:RMS script
Reply by: sound-kobo
Date:1/13/2007 1:02:51 AM

This script looks promising, very promising. I am doing similar voice related things...

I don't understand the output though. Why do the RMS values come out to negative numbers?

for example:
-14.1 00.952 ok01.wav
-14 00.853 ok02.wav
-14.4 00.783 ok03.wav
-15.3 01.070 on01.wav

Subject:RE: Statistics:RMS script
Reply by: _TJ
Date:1/13/2007 2:17:28 PM

RMS Values are measured in Decibels, (dB), Which is a logarithmic scale,
so negative values are < 100% and positive values are > 100%

http://en.wikipedia.org/wiki/Decibel

tj

Subject:RE: Statistics:RMS script
Reply by: sound-kobo
Date:1/13/2007 7:42:52 PM

Doh! true indeed - missed the forest for the trees. :)

This may come across even sillier but....

The output from StatisticsTest.cs in the SDK gives a positive decimal value for the RMSLevel. What am I missing?

Statistics are up to date
stat[0] = SoundForge.SfAudioStatistics
Start 0
Length 39392
RMSLevel 0.184964267939442
MinValue -0.94732666015625

Subject:RE: Statistics:RMS script
Reply by: _TJ
Date:1/15/2007 2:18:15 PM

I guess I should say USUALLY measured in decibels. The RMSLevel
here is a gain value. (i.e 1.0 is 100%)

Go Back