Skip to content

Instantly share code, notes, and snippets.

@celesteh
Last active April 19, 2024 17:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save celesteh/77ee808b2d1a92c95684c1fa08e760e8 to your computer and use it in GitHub Desktop.
Save celesteh/77ee808b2d1a92c95684c1fa08e760e8 to your computer and use it in GitHub Desktop.
<html>
<head>
<title>Equal Temperaments</title>
</head>
<body>
<p>Tuning scales is about ratios. We multiply the root frequency by a given ratio to get a note in the scale. In Equal Temperament, all ratios are equal, the 12th root of 2. Which is 2<sup>1&frasl;12</sup>. We multiply a frequency by that to get the next frequency in the scale. When we've gone through all 12, we get the octave. (2<sup>1&frasl;12</sup>)<sup>12</sup> = 2.</p>
<p>Let's say we want the 3rd note in the chromatic scale. We have the root and multiply by the ratio for the second and then for the third. For the fourth, we do it three times. For the fifth, four times. Therefore, for any chromatic scale step 𝘯, we multiply the root by 2<sup>(𝘯-1)&frasl;12</sup>
<p>But, especially when we're using computers, we can try out putting the notes in different places! What if we have 10 steps per octave? Then our ratio is Which is 2<sup>1&frasl;10</sup>. The composer William Sethares has written music using 10 tone equal temperament and in other unusual tunings, which you can listen to on <a href="https://sethares.engr.wisc.edu/otherperson/all_mp3s.html">his web page</a>.</p>
<p>We can even forego octaves entirely. The Bohlen-Pierce scale is based on divisions of 3, rather than 2. When people use equal temperament with that scale, they typically have 13 steps in the octave, which makes their ratio 3<sup>1&frasl;13</sup>. The composer Elaine Walker is one of many who has written music using Bolhen Pierce and you can find examples on <a href="http://ziaspace.com/_academic/BP/">her website.</a></p>
<p>We can also try out different tunings ourselves! Below, you can try out different Equally Tempered scales. Change the steps value for the number of divisions you want. If you want to try out Bohlen-Pierce, change the octave ratio to 3. Or try whatever tickles your fancy.</p>
<form id="tuner">
<label for="freq">Base Frequency:</label>
<input type="number" id="freq" name="freq" value="440"><br/>
<label for="octave">Octave ratio:</label>
<input type="number" id="octave" name="octave" value="2"><br/>
<label for="steps">Number of chromatic steps:</label>
<input type="number" id="steps" name="steps" value="12"><br/>
<button type="button" onclick="calculate_ratio()">Calculate ratio</button>
<button type="button" onclick="play_chromatic()">Listen to your tuning</button>
<button type="button" onclick="play_12tet()">Compare to 12tet</button><br />
</form>
<p>Your tuning ratio is <span id="pretty_ratio"> 2<sup>1&frasl;12</sup></span>, which is equal to <span id="decimal">1.0594630943592953</span><p>
<p>12tet's ratio of 2<sup>1&frasl;12</sup> is equal to 1.0594630943592953</p>
<script>
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var ttet_ratio = Math.pow(2, 1/12);
var octave = 2, steps = 12;
var user_ratio = ttet_ratio;
var ttet_arr, user_arr, notes, ttet_oct, user_oct;
ttet_arr = calculate_scale(ttet_ratio, 12);
user_arr = ttet_arr;
ttet_oct = calculate_octatonic(ttet_ratio, 12, 2);
user_oct = ttet_oct;
function calculate_ratio() {
octave = Number(document.getElementById("octave").value);
steps = Number(document.getElementById("steps").value);
document.getElementById("pretty_ratio").innerHTML =
" ".concat(octave).concat("<sup>1&frasl;").concat(steps).concat("</sup>");
var old_user_ratio = user_ratio;
user_ratio = Math.pow(octave, 1/steps);
document.getElementById("decimal").innerHTML = user_ratio;
if ( old_user_ratio != user_ratio) {
user_arr = calculate_scale(user_ratio, steps);
user_oct = calculate_octatonic(user_ratio, steps, octave);
}
}
function calculate_scale(ratio, steps) {
steps = steps+1;
console.log(steps, ratio);
var arr = new Array(steps);
for (let i = 0; i < steps; i++) {
//console.log(i);
arr[i] = Math.pow(ratio, i);
}
console.log(arr);
return arr;
}
function calculate_octatonic(ratio, steps, octave){
steps = steps+1;
var arr = new Array(1);
arr[0] = 1;
var index = 0;
var keep_looping = true;
while (index < steps) {
index += 2;
if (index < steps){
arr.push(Math.pow(ratio, index));
index++;
if (index < steps) {
arr.push(Math.pow(ratio, index));
}
}
}
if (arr[arr.length-1] != octave){
arr.push(octave);
}
return arr;
}
function playNote(frequency, duration) {
// create Oscillator node
var oscillator = audioCtx.createOscillator();
oscillator.type = 'square';
oscillator.frequency.value = frequency; // value in hertz
oscillator.connect(audioCtx.destination);
oscillator.start();
setTimeout(
function() {
oscillator.stop();
playList();
}, duration);
}
function playList() {
if (notes.length > 0) {
note = notes.pop();
console.log(note);
console.log(notes.length);
if (Array.isArray(note)) {
playNote(note[0],note[1]);
} else {
playNote(note, 500);
}
}
}
function playScale(arr) {
var freq = Number(document.getElementById("freq").value);
var steps = arr.length;
//var i = steps;
notes = new Array((steps*2)-2);
//console.log((steps*2)+1);
for(let i=0; i < (steps); i++){
notes[i] = arr[i] * freq;
notes[steps+i] = arr[steps-i-1] * freq;
//console.log(i, arr[i], steps+i, arr[steps-i-1]);
}
//console.log(notes);
playList();
}
function play_chromatic() {
calculate_ratio();
playScale(user_arr);
}
function play_12tet(){
playScale(ttet_arr);
}
function debussy(scale){
var freq = Number(document.getElementById("freq").value);
var crotchet = 700;
var quaver = crotchet/2;
var semiquaver_triplet = quaver / 3;
notes = [
[scale[1] * freq, semiquaver_triplet],
[scale[2] * freq, semiquaver_triplet],
[scale[3] * freq, semiquaver_triplet],
[scale[4] * freq, crotchet * 3],
[scale[3] * freq, crotchet * 2],
[scale[2] * freq, crotchet],
[scale[1] * freq, crotchet],
[scale[0] * freq, crotchet],
[scale[0] * freq, crotchet * 2]
];
notes.reverse();
playList();
}
</script>
<p>It can sometimes be difficult to hear the differences in pitches just going up and down a chromatic scale. Modes like major and minor are very strongly tied to a 12 note chromatic scale and it doesn't make sense to try to, say, play a 10 note major scale. However, the octatonic scale is a mode that can potentially work for any tuning. It alternates whole and half steps. Perhaps listening to the octatonic versions of your scale and 12tet will demonstrate the differences more clearly.</p>
<form id="octatonic">
<button type="button" onclick="calculate_ratio();playScale(user_oct);">Listen to your tuning in octatonic</button>
<button type="button" onclick="playScale(ttet_oct);">Compare to 12tet octatonic</button><br />
</form>
<p>Or we can try a phrase by Debussy:</p>
<form id="octatonic">
<button type="button" onclick="calculate_ratio();debussy(user_oct);">Debussy in your tuning</button>
<button type="button" onclick="debussy(ttet_oct);">Debussy in 12tet</button><br />
</form>
</body>
</html>
@celesteh
Copy link
Author

Note that the major, minor etc scales are subsets of the chromatic scale.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment