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%) |