In my previous post I described how I create seamless music loops in Cubase and Sound Forge. I also mentioned that I have a Javascript for Sound Forge that I use to save time in performing the task to crop out the center third of the audio file along with fading the start and finish of the loop to remove any clicks at the loop point.

You can Download Seamless Loop Javascript for Sound Forge. Remember that you can't just magically rung this script on any old piece of audio to make a seamless loop of it - you need to follow the directions of the YouTube Tutorial to produce the audio file suitable for making a seamless loop.

Let's have a look at what the script does


Basically, I took the sample script that you get with Sound Forge that Crops and Fades a piece of audio. I then made the following alterations:
var smpLength : Int64 = Math.round(wnd.File.Length / 3);

The above line of code creates the variable smpLength, which is a 64 bit integer, to a third of the length of the audio file that is currently open and active in Sound Forge. I use the Math.round function to ensure it's a whole number as samples can't be decimals, it's either a sample or not =)
var asel : SfAudioSelection = new SfAudioSelection(smpLength, 
smpLength);

I then create the variable asel which is a new selection of audio. I use the arguments (smpLength, smpLength) for the constructor because I wan't it to start the selection one third into the audio file and I want the duration to also be a third. The script has now selected exactly the center third of the audio.
var ccFade : Int64 = 20;

We then set the variable ccFade to 20 which represents how many samples we want to fade. As you can see 20 samples is very little (0.00045 seconds if the sample rate is 44.1kHz) and this is because we just want to avoid the speaker having to abruptly jump to the start value other than 0 which would create and audible click.

Note: You may need to change ccFade depending on the music you are looping! For loud and aggressive music 20 samples is usually good, but for slow music such as sweeping strings and pads you may need around 100 samples. The reason for this is that 20 samples is still quite fast and it'll create a small percussive sound.

The rest of the script is pretty much the same as the Crop and Fade script I used as a base so it's a very small and simple modification.

You can also see the script in action in the YouTube tutorial video at 7:00.



Here is the entire script in clear text as well - or you can download it at the top of the post.
import System;
import System.Windows.Forms;
import SoundForge;

/*
Script: Seamless Loop Extractor
Author: Stefan Persson - Imphenzia Soundtrack - http://soundtrack.imphenzia.com

Run this script on an audio file were a piece of music is repeated 3 times exactly.
To create such an audio file in the first place copy a set of measures in your
sequencer software three times and export the audio from just the three sets of
measures. E.g. you want to loop 4 measures of music, make two adjacent copies of
the measures making it 12 measures in total. Export these 12 measures (no more and
no less) as an audio file.

The script will then crop out the center third of the audio file and make a very
short crossfade in the beginning and the end of the file to ensure that there is
no clicking at the loop points. What you should end up with is a perfect seamless
loop.

The crossfades are only 20 samples in length which should be inaudible for the ear
but without the crossfade the sample would start with a "click" as every audio
file should start and end at 0dB exactly.

NOTE! For slow pieces of music you may want to increase the variable ccFade from
20 to around 80 if there is an audible percussive click at the loop point.

(This script is based on the "Crop and Fade" sample script)
*/

public class EntryPoint {
public function Begin(app : IScriptableApp) {

var wnd = app.ActiveWindow;
if (null == wnd) return;

// We are interested in exactly one third of the samples in the center of the
// audio file, set smpLength to this value
var smpLength : Int64 = Math.round(wnd.File.Length / 3);

// Construct a new selection starting one third into the audio file with the
// duration of a third of the audio file
var asel : SfAudioSelection = new SfAudioSelection(smpLength, smpLength);

// Set the length of the fade to only 20.
// This can be changed and usually values between 10 and 100 will work, 10
// for aggressive music and 100 for very slow music.
var ccFade : Int64 = 20;

var file : ISfFileHost = wnd.File;

var fCancel = false;
var idUndo : int = file.BeginUndo("Crop and Fade");

file.CropAudio(asel.ccStart,asel.ccLength);
wnd.SelectionLength = 0; // remove the selection lest it confuse us.

file.DoEffect("Graphic Fade", "-6 dB exponential fade in",
new SfAudioSelection(0, ccFade),
EffectOptions("EffectOnly"));
var result : SfStatus = file.WaitForDoneOrCancel();
if (result != SfStatus.Success) {
fCancel = true;
} else {
file.DoEffect("Graphic Fade", "-6 dB exponential fade out",
new SfAudioSelection(wnd.File.Length - ccFade, ccFade),
EffectOptions("EffectOnly"));
result = file.WaitForDoneOrCancel();
if (result != SfStatus.Success) fCancel = true;
}

file.EndUndo(idUndo, fCancel);
DPF("Done - {0}", fCancel ? "failed and rewound changes" : "success");
}

public function FromSoundForge(app : IScriptableApp) {
ForgeApp = app;
app.SetStatusText(String.Format("Script '{0}' is running.", Script.Name));
Begin(app);
app.SetStatusText(String.Format("Script '{0}' is done.", Script.Name));
}

public var ForgeApp : IScriptableApp = null;
public function DPF(sz) { ForgeApp.OutputText(sz);}
public function DPF(sz,o) { ForgeApp.OutputText(System.String.Format(sz,o)); }
public function DPF(sz,o,o2) { ForgeApp.OutputText(System.String.Format(sz,o,o2)); }

public function DPF(sz,o,o2,o3) { ForgeApp.OutputText(System.String.Format(sz,o,o2,o3)); }

} // class EntryPoint