-
Notifications
You must be signed in to change notification settings - Fork 0
/
marathonlooper.html
79 lines (63 loc) · 6.57 KB
/
marathonlooper.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<!DOCTYPE html>
<html lang="en-us">
<head>
<title>Marathon: Looper, or, Looping Music pre-Aleph One 1.7</title>
<link rel="stylesheet" type="text/css" href="https://code.cdn.mozilla.net/fonts/fira.css">
<link rel="stylesheet" type="text/css" href="css.css">
<script>
function sortTable(table, col, reverse) {
var tb = table.tBodies[0], // use `<tbody>` to ignore `<thead>` and `<tfoot>` rows
tr = Array.prototype.slice.call(tb.rows, 0), // put rows into array
i;
reverse = -((+reverse) || -1);
tr = tr.sort(function (a, b) { // sort rows
return reverse // `-1 *` if want opposite order
* (a.cells[col].textContent.trim() // using `.textContent.trim()` for test
.localeCompare(b.cells[col].textContent.trim(), undefined, {numeric: true})
);
});
for(i = 0; i < tr.length; ++i) tb.appendChild(tr[i]); // append each row in order
}
function makeSortable(table) {
var th = table.tHead, i;
th && (th = th.rows[0]) && (th = th.cells);
if (th) i = th.length;
else return; // if no `<thead>` then do nothing
while (--i >= 0) (function (i) {
var dir = 1;
th[i].addEventListener('click', function () {sortTable(table, i, (dir = 1 - dir))});
}(i));
}
function makeAllSortable(parent) {
parent = parent || document.body;
var t = parent.getElementsByTagName('table'), i = t.length;
while (--i >= 0) makeSortable(t[i]);
}
window.onload = function () {makeAllSortable();};
</script>
</head>
<body>
<header>
<title>Marathon: Looper</title>
<h1 style="margin-bottom: 4px;" class="petitecaps centred">Marathon: Looper? I hardly know ’er!</h1>
<h4 style="margin: 4px 0px;" class="centred">or, How I Learned to Remove Brief Gaps and Love Zero Crossings</h4>
<h4 style="margin: 4px 0px 16px;" class="centred">or, Looping Music pre-Aleph One 1.7: A Duty-Dance with Death</h4>
<p>This information on looping music in Aleph One has been split off from my <a href="mapmaking.html">advanced mapmaking guide</a> because Aleph One 1.7 redoes the music engine in a way that makes much of this unnecessary. If you’re interested in supporting old versions of Aleph One, you’ll still need to follow these steps to make music loop seamlessly (and you’ll need to test them in Aleph One 1.6.1 or earlier), but if you’re only interested in supporting Aleph One 1.7 or later, you can ignore the information found here.</p>
<p>Before consulting my advanced guide, you’ll probably want to start with my <a href="mapmaking101.html">beginners’ guide</a>. Please <a href="aboutme.html">contact me</a> if you notice any errors or omissions.</p>
</header>
<h1 id="looper">Looping Music in Aleph One pre-1.7</h1>
<p>For the record, I’m not talking about the music restarting after it fades out – Aleph One does that by default. I’m talking about seamless loops, where the ending leads straight back into the beginning. Aleph One <em>could</em> do this before version 1.7, but it was very finicky and dependent upon a few things:</p>
<ol>
<li>It didn’t work with MP3 files, only Ogg Vorbis, WAV, AIFF, and (in Aleph One 1.6.1) FLAC. The reason for this is that MP3 inserts junk samples at the start and end of a track, and Aleph One’s music player didn’t know enough to skip these. Transcoding directly from MP3 to one of these other formats wouldn’t help; you’d need to edit the junk samples out and save as another format. If you plan to save an edited MP3 as Ogg Vorbis, I recommend following <a href="remastering.html">my procedure for upmastering audio</a> to mitigate <a href="https://en.wikipedia.org/wiki/Generation_loss">generation loss</a>. (To be clear, upmastering can’t produce perfect repliche of the sounds MP3 compression stripped out – that’s impossible. You should definitely use lossless audio sources if suitable ones are available.)</li>
<li>By default, Aleph One parses audio files in 1,024-sample chunks (roughly 23 milliseconds with a 44.1 kHz sample rate) and won’t reload the audio file (or load the next file) until it’s in the final sample block. Annoyingly, the chunk size can vary based on a setting in the preferences file (and you must actually load the preferences in a text editor to see the setting), but it’s usually 1,024 or 512 (thus, I’m oversimplifying here and assuming 1,024-sample blocks).
<p>Thus, in this case, the number of samples modulo 1024 should be as close to 1023 as possible. (You can find out how many samples your music file has in any audio editor worth its salt.) In other words, the ideal number of samples for a loop is <strong>(1024 × <em>n</em>) − 1</strong>, where <em>n</em> is some integer. It’s acceptable for it to be <strong>(1024 × n) − 2</strong>, <strong>(1024 × <em>n</em>) − 8</strong>, <strong>(1024 × <em>n</em>) − 4</strong>, and so on, but the more the distance increases, the longer and more perceptible the delay gets. The longest delay results from <strong>1024 × <em>n</em></strong> samples.</p>
Manipulating your song’s length by fewer than 23 milliseconds probably won’t audibly affect the rhythm if you’re careful to fill up the space you add with audio information that isn’t out of place, or to trim audio congruously. (<a href="https://izotope.com/products/rx" target="_blank">iZotope RX</a>’s <strong>Interpolate</strong> function can help to generate audio that will fit.) If silence ends up getting tossed into there, though, you’ve got a problem.</li>
<li>Songs must start and end at zero crossings – in both channels, for stereo audio. A zero crossing is a point where the waveform crosses the midpoint (i.e., −∞ dB). Here’s an example in iZotope RX (zoomed in quite a lot both vertically and horizontally to make it clearly visible).</li>
</ol>
<div class="image"><img src="zerocrossing.png" width="800" height="700" title="Illustration of a zero crossing in iZotope RX" alt="Illustration of a zero crossing in iZotope RX" /></div>
<ol start="4">
<li>Even this may be insufficient to get a seamless loop, so I recommend avoiding especially loud starting points. A cymbal crash, for example, is far from ideal. An acoustic guitar strum is better.</li>
</ol>
<p class="sectionbreak noprint"><a href="#top">Back to top</a> · <!--<a href="#toc">Table of contents</a> · --><a href="mapmaking101.html">Mapmaking (basic)</a> · <a href="mapmaking.html">Mapmaking (advanced)</a> · <a href="aboutme.html">Contact me</a> · <a href="index.html">Website index</a></p></li>
</body>
</html>