Making smooth loops in sample-based audio
Some of us still enjoy making music the oldskool way; using sample-based instruments and targeting older filetype formats in order to support game-developers on the classic platforms. For example, the Amiga MOD format, as well as the FastTracker 2 XM format, Scream Tracker S3M and Impulse Tracker IT.
Creating these filetypes is about working with limitations. That's a fun part of the challenge. The MOD format only gives us 4 channels of 8-bit resolution. And if we want to make our MODs attractive to Amiga game-developers, we have to produce MODs that are very small in filesize. Because game-developers targeting a stock Amiga 500 will typically want MODs that are only between 20 kB and 80 kB in filesize, while game-developers targeting a stock Amiga 1200 typically lets you get away with MODs between 150 kB and 250 kB.
There are really only 3 effective ways we can produce such a small filesize:
- Minimise the number of patterns
- Use low samplerates
- Use instruments with a short length
Minimising the number of patterns in your MOD is a matter of reusing patterns on the expense of variation in the track. Sometimes it also helps to use a clever mix of Fxx tempo/speed commands and E6x pattern loop commands.
Turning the samplerate down is a simple matter of resampling the instruments, and maybe add a bit of treble boost to bring back some of the higher frequencies that were lost in the process. (Keep a version of the MOD with higher samplerates though - other platforms don't have the same limitations).
And in order to minimise the length of our instruments, we can use loop points, on the expense of variation in the sound.
Creating loops in our instruments is somewhat of a mission of its own. Who doesn't remember spending hours in the good old days trying to find an optimal pair of loop points in a string chord, only to give up in the end and settle for the very apparent hick-up when the instrument looped? As if there was a scratch in the vinyl record.
Some of us might actually still use that approach, and sometimes it'll be ok too. As long as the mix with other instruments blurs out the hick-up, then it'll be fine. But that's not always the case.
What only few of us knew back then, most of us have since come to know as general knowledge: There are ways to create smooth loops without hick-ups.
In this tutorial we'll go through 3 different methods of achieving such a smooth loop. Two that you definitely already know about, and one that you probably didn't know about:
- Single cycle loop
- Crossfade loop
- Monotonic chord loop
Single cycle loop
When the focus is on producing a small filesize, it doesn't get more effective than the single cycle loop. This method is used extensively in chip tunes, which are typically tiny in filesize exactly because many of the instruments consists only of such single cycle loops.
This is where you loop a single wave-length (or two) in the waveform somewhere. Or the whole instrument could consist of nothing but such a single wave-length loop, thus resulting in a very small filesize - usually less than 100 frames!
Single cycle loops will always give a monotonic "lifeless" sound, so you will have to add some life (intonation) to the instrument yourself, using commands like 4xy vibrate and/or 7xy tremolo. But the biggest problem with single cycle looped instruments, is one that is often overlooked: Tuning.
In order to create a single cycle loop in tune (and with a clean sound as well) with the first part of the instrument, the wave-length has to be an integer number.
Let's say we want to loop a C, meaning a 261,63 Hz tone. And let's say the samplerate for this tone is 16574 Hz. This will give us a wave-length of 16574 / 261,63 = 63,35 frames, which means that we need a single cycle loop of 63,35 frames in order to create a clean loop in tune with the first part of the sample.
We can't do that though, because loop points has to be integer numbers. So the first thought you might get, will be to just round it down to 63. And that would be ok if we were creating an XM or S3M or IT. But loop points in a MOD must be a multiple of 2. So we have to round it up to 64 frames instead.
Rounding the loop size up to 64 frames will give us a tone of 16574 / 64 = 258,97 Hz instead of 261,63 Hz. This means the tone will "bend down" a little when it reaches our single cycle loop, and it might also produce a bit of alias noise, because the loop size doesn't match the actual wave-length of the tone frequency. And that's how you may end up with a track where multiple instruments sound completely out of tune with each other.
How to fix this?
Well it's quite simple really. You just have to make sure that the samplerate is an integer multiple of the tone frequency.
For a tone frequency of 261,63 Hz, the "correct" samplerate to use could be 261,63 * 64 = 16744,32 Hz. That'll give you have a nice clean sound in tune with the tone, using a loop of as close to 64 frames you can get with a 261,63 Hz tone.
Any integer multiple of the tone-frequency will give you a single cycle length of that factor. A samplerate of 261,63 * 30 will give you a wave-length of about 30 frames. So it really is that simple.
For an absolute perfect single cycle loop, where the wave-length is an exact integer, you should use integer tone frequencies as well. Instead of a C, go for the A at 220 Hz at a samplerate of 220*64 = 14080 Hz.
This of course means you'll have to resample all of your other instruments as well, in order for them to be in tune with each other. And you'll also have to accept that the tones played in the MOD won't match the tones of the source of the instruments. But it'll totally be worth it when listening to the end result.
As a side note: Although any integer multiple of the tone-frequency will work, there are some advantages in always using a factor of 2 to the power of n (where n can be any integer as long as the result is within the range of supported samplerates). In other words; aim for a factor of 16, 32, 64, 128 etc. Because then it also becomes much easier to
- have the 9xx offset command always start at a zero-amplitude spot, to minimise click'n'pops
- handle harmonic overtones: They will always be exactly n-1 octaves higher than the tone, meaning they will be in tune with each other
- convert your track to the Super Nintendo (because the SPC700 soundchip in the SNES require loop points to be a multiple of 16, due to its BRR sample format)
Crossfade loop
As mentioned, a single cycle loop results in a somewhat lifeless monotonic sound. If we want more dynamic intonation in the sound than what we can produce with effect commands, then we need to loop more than a single cycle of audio. Just like we did with the old "scratch in the vinyl record" method. Except we'd like to avoid the scratch part.
Most of us had no clue back in the old days, but nowadays we know about this technique for creating a smooth loop without any such hick-ups: Crossfading.
If we record a 2-second long string chord, we can then
- cut it into two halves, each 1 second long
- fade in the first part
- fade out the second part
- mix those two together
That's how you create a 1-second long crossfaded loop. It should sound smooth without any hick-up.
But as we all know, nothing is ever that simple. There are of course other things we need to be aware of when making a crossfaded loop: Phases.
If you simply split a random length of audio recording into two parts, the chance of the phases matching each other is slim to none.
And while this may sometimes create an awesome phaser effect that you might quickly decide to stick with, you will simply get a completely different phaser effect for the next crossfaded loop. So you'll end up with string chords that each has a very different sound to them. Not optimal.
To create an optimal crossfaded loop, you first have to locate a natural loop in the sound. Simply listen to the audio until you detect something that sounds somewhat like a loop. That's how long your crossfaded loop is going to be as well.
Then zoom into the waveform and find the two spots where the frames looks similar. Just like you would when creating a "vinyl scratch loop". Then cut such two natural sounding loops next to each other, and make sure they are in phase. The beginning of both of them should look somewhat the same. Not necessarily 100% identical, but somewhat similar.
Fade in the first part, and fade out the second part. Then mix together. That should give you a perfect crossfaded loop without any hick-ups and without any unwanted phase effect.
Use that approach for all your crossfaded chord strings, and it should give you chord strings with the same sound.
Monotonic chord loop
While the crossfade technique will indeed give you a loop without any hick-ups, you will still be able to hear that it's a loop, because it repeats the same sound pattern over and over again. This is unavoidable with loops that contain changes in pitch and volume. You can make it less noticeable of course, by making the loop longer. But we'll need a loop of several seconds for that to work, and that will be on the expense of filesize.
What if we want a chord that we literally can't hear is looping, while also keeping filesize down to a minimum? Can we do that?
Absolutely! We simply need to go back to the monotonic sound again; a chord that sounds like 3 single-cycle tones. And combine such 3 monotonic waveforms with something called "just intonation".
Let's try it out by creating a D major chord at a samplerate of 14080 Hz.
A D major chord consist of the 3 tones D, F# and A. The D is at 587,33 Hz, and at a samplerate of 14080 Hz, that gives a wave-length of 23,97 frames. The F# is at 739,99 Hz, giving a wave-length of 19,03 frames. And the A is at 880 Hz, giving a wave-length of 16 frames.
As we learned with the single cycle loop, the goal is to use a combination of tone frequency and samplerate that'll give us a wave-length that is an integer number. This is easy to achieve for single tones, but impossible to do for all 3 tones in a chord - unless we cheat a little bit...
If we round 23,97 up to 24, and 19,03 down to 19, then we'll have 3 wave-lengths that is each an integer number.
Then consequence is that the D and F# will be slightly out of tune. The D will now land at 586,67 Hz instead of 587,33 Hz, which means it'll be off by 0,11%. And the F# will land at 741,05 Hz instead of 739,99 Hz, which means it'll be off by 0,14%. In both cases that's such a small deviation that it doesn't matter, because it won't be noticeable.
So now we have 3 integer wave-lengths of 16, 19 and 24, which means that the ratio between tone frequencies are also integer numbers. And this means we're now using "just intonation" tuning.
All we have to do now, is to find the first integer number that - when divided with each of the 3 wave-lengths - results in an integer number for all three. I wrote a small little tool that simply counts an integer variable up until it finds that number. And that number tells you what the size of the loop will be. In this case: 912!
Yes, you read that right. And I bet you probably won't believe it till you hear it. But it's true: You can actually make a chord, that you can't hear is a chord (because it's monotonic), using only 912 frames (because it uses "just intonation" tuning).
912 frames / 16 frames per cycle = 57 cycles
912 frames / 19 frames per cycle = 48 cycles
912 frames / 24 frames per cycle = 38 cycles
At 912 frames each tone will have completed an integer number of cycles.
Ok, so how to do this?
Well there are several ways, but let's use Milkytracker as our tool: You can use the Generator in the Sample Editor. Create a new instrument containing 14080 frames. Then generate a tone of 586,67 Hz at 30% volume. Use any kind of waveform you want; Sine, Triangle, Square or Sawtooth. Add another tone of 741,05 Hz at 30% volume again. And lastly a tone of 880 Hz again at 30%. Then set loop start to 0 and loop end to 912, and listen to the wonder that is a short monotonic loop without hick-ups and without being able to hear that it is a loop - in only 912 frames.
You can play around with different samplerates and tone frequencies. Certain tones will deviate too much at certain samplerates. So the goal is to find the optimal frequencies for both the tones and samplerate, while at the same time having all the other instruments in the track stay in tune.
Back to table of contents