--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ html {
+ background-color: gray;
+ }
+ body {
+ font-family: sans-serif;
+ width: 80%;
+ margin: 1% auto;
+ padding: 1%;
+ border: 1px solid darkgray;
+ background-color: white;
+ }
+ </style>
+ <script>
+
+ const freq = {
+ "c":[
+ 16.35160,
+ 32.70320,
+ 65.40639,
+ 130.8128,
+ 261.6256,
+ 523.2511,
+ 1046.502,
+ 2093.005,
+ 4186.009
+ ],
+ "cs":[
+ 17.32391,
+ 34.64783,
+ 69.29566,
+ 138.5913,
+ 277.1826,
+ 554.3653,
+ 1108.731,
+ 2217.461,
+ 4434.922
+ ],
+ "d":[
+ 18.35405,
+ 36.70810,
+ 73.41619,
+ 146.8324,
+ 293.6648,
+ 587.3295,
+ 1174.659,
+ 2349.318,
+ 4698.636
+ ],
+ "ds":[
+ 19.44544,
+ 38.89087,
+ 77.78175,
+ 155.5635,
+ 311.1270,
+ 622.2540,
+ 1244.508,
+ 2489.016,
+ 4978.032
+ ],
+ "e":[
+ 20.60172,
+ 41.20344,
+ 82.40689,
+ 164.8138,
+ 329.6276,
+ 659.2551,
+ 1318.510,
+ 2637.020,
+ 5274.041
+ ],
+ "f":[
+ 21.82676,
+ 43.65353,
+ 87.30706,
+ 174.6141,
+ 349.2282,
+ 698.4565,
+ 1396.913,
+ 2793.826,
+ 5587.652
+ ],
+ "fs":[
+ 23.12465,
+ 46.24930,
+ 92.49861,
+ 184.9972,
+ 369.9944,
+ 739.9888,
+ 1479.978,
+ 2959.955,
+ 5919.911
+ ],
+ "g":[
+ 24.49971,
+ 48.99943,
+ 97.99886,
+ 195.9977,
+ 391.9954,
+ 783.9909,
+ 1567.982,
+ 3135.963,
+ 6271.927
+ ],
+ "gs":[
+ 25.95654,
+ 51.91309,
+ 103.8262,
+ 207.6523,
+ 415.3047,
+ 830.6094,
+ 1661.219,
+ 3322.438,
+ 6644.875
+ ],
+ "a":[
+ 27.50000,
+ 55.00000,
+ 110.0000,
+ 220.0000,
+ 440.0000,
+ 880.0000,
+ 1760.000,
+ 3520.000,
+ 7040.000
+ ],
+ "as":[
+ 29.13524,
+ 58.27047,
+ 116.5409,
+ 233.0819,
+ 466.1638,
+ 932.3275,
+ 1864.655,
+ 3729.310,
+ 7458.620
+ ],
+ "b":[
+ 30.86771,
+ 61.73541,
+ 123.4708,
+ 246.9417,
+ 493.8833,
+ 987.7666,
+ 1975.533,
+ 3951.066,
+ 7902.133
+ ]
+ };
+
+ const notes = ["c", "cs", "d", "ds", "e", "f", "fs", "g", "gs", "a", "as", "b"];
+
+ function calculateFilter () {
+ let points = [];
+ for (note of notes){
+ if (document.getElementById(note).checked) {
+ for (let i = 0; i < 9; i++) {
+ if (document.getElementById(`oc${i}`).checked) {
+ points.push(freq[note][i]);
+ }
+ }
+ }
+ }
+ const ampHigh = document.getElementById("base").value;
+ const ampLow = document.getElementById("lower").value;
+ let fPoints = [];
+ let aPoints = [];
+
+ for (point of points) {
+
+ let note = 12 * Math.log2(point / 440) + 49;
+ let lowNote = note - document.getElementById("width").value;
+ let highNote = note + Number(document.getElementById("width").value);
+ let lowPoint = Math.pow(2, ( ( lowNote-49 ) / 12 )) * 440;
+ let highPoint = Math.pow(2, ( ( highNote-49 ) / 12 )) * 440;
+
+ console.log({
+ "Note": note,
+ "Low Note": lowNote,
+ "High Note": highNote,
+ "Low Frequency": lowPoint,
+ "High Frequency": highPoint
+ });
+
+ if (document.getElementById("squareedges").checked) {
+ fPoints = fPoints.concat([lowPoint, lowPoint+0.00001, highPoint-0.00001, highPoint]);
+ aPoints = aPoints.concat([ampHigh, ampLow, ampLow, ampHigh]);
+ }
+ else {
+ fPoints = fPoints.concat([lowPoint, point, highPoint]);
+ aPoints = aPoints.concat([ampHigh, ampLow, ampHigh]);
+ }
+ }
+
+ let string = "FilterCurve:";
+ for (let i = 0; i < fPoints.length; i++) {
+ string += `f${i}="${fPoints[i]}" `
+ }
+ string += 'FilterLength="8191" InterpolateLin="0" InterpolationMethod="B-spline" '
+ for (let i = 0; i < aPoints.length; i++) {
+ string += `v${i}="${aPoints[i]}" `
+ }
+ document.getElementById("stats").innerHTML = `Generated ${aPoints.length} points. Will work with Audacity?: ${aPoints.length <= 200} (max. 200 points)`;
+
+ const file = new File([string], 'filter.txt', {
+ type: 'text/plain',
+ });
+ const link = document.createElement('a')
+ const url = URL.createObjectURL(file)
+ link.href = url
+ link.download = file.name
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+ window.URL.revokeObjectURL(url)
+ }
+ </script>
+ </head>
+ <body>
+ <h1>Key removal filter generator</h1>
+ <form>
+
+ <fieldset>
+ <legend>Filter Amplification</legend>
+ <input type="number" id="lower" name="lower">
+ <label for="lower">dB</label><br>
+ <label for="lower">Lower amplification</label><br>
+ <input type="number" id="base" name="base">
+ <label for="base">dB</label><br>
+ <label for="base">Base amplification</label><br>
+ </fieldset><br>
+
+ <fieldset>
+ <legend>Octaves</legend>
+ <input type="checkbox" id="oc8" name="oc8" value="oc8">
+ <label for="oc8">8th</label><br>
+ <input type="checkbox" id="oc7" name="oc7" value="oc7">
+ <label for="oc7">7th</label><br>
+ <input type="checkbox" id="oc6" name="oc6" value="oc6">
+ <label for="oc6">6th</label><br>
+ <input type="checkbox" id="oc5" name="oc5" value="oc5">
+ <label for="oc5">5th</label><br>
+ <input type="checkbox" id="oc4" name="oc4" value="oc4">
+ <label for="oc4">4th</label><br>
+ <input type="checkbox" id="oc3" name="oc3" value="oc3">
+ <label for="oc3">3rd</label><br>
+ <input type="checkbox" id="oc2" name="oc2" value="oc2">
+ <label for="oc2">2nd</label><br>
+ <input type="checkbox" id="oc1" name="oc1" value="oc1">
+ <label for="oc1">1st</label><br>
+ <input type="checkbox" id="oc0" name="oc0" value="oc0">
+ <label for="oc0">0th</label><br>
+ </fieldset><br>
+
+ <fieldset>
+ <legend>Notes</legend>
+ <input type="checkbox" id="c" name="c" value="c">
+ <label for="c">C</label><br>
+ <input type="checkbox" id="cs" name="cs" value="cs">
+ <label for="cs">C#/Db</label><br>
+ <input type="checkbox" id="d" name="d" value="d">
+ <label for="d">D</label><br>
+ <input type="checkbox" id="ds" name="ds" value="ds">
+ <label for="ds">D#/Eb</label><br>
+ <input type="checkbox" id="e" name="e" value="e">
+ <label for="e">E</label><br>
+ <input type="checkbox" id="f" name="f" value="f">
+ <label for="f">F</label><br>
+ <input type="checkbox" id="fs" name="fs" value="fs">
+ <label for="fs">F#/Gb</label><br>
+ <input type="checkbox" id="g" name="g" value="g">
+ <label for="g">G</label><br>
+ <input type="checkbox" id="gs" name="gs" value="gs">
+ <label for="gs">G#/Ab</label><br>
+ <input type="checkbox" id="a" name="a" value="a">
+ <label for="a">A</label><br>
+ <input type="checkbox" id="as" name="as" value="as">
+ <label for="as">A#/Bb</label><br>
+ <input type="checkbox" id="b" name="b" value="b">
+ <label for="b">B</label><br>
+ </fieldset><br>
+
+ <fieldset>
+ <legend>Misc</legend>
+ <input type="number" id="width" name="width" step="0.1">
+ <label for="width">Semitones</label><br>
+ <label for="width">Width</label><br>
+ <input type="checkbox" id="squareedges" name="squareedges" value="squareedges">
+ <label for="squareedges">Square</label><br><br>
+ </fieldset><br>
+
+ <input type="button" onclick="calculateFilter();" value="Generate"><br><br>
+
+ <textarea readonly name="stats" id="stats" rows="1" style="width:100%;">Stats</textarea><br>
+
+ <textarea readonly name="textual" id="textual" style="width:100%; height:200px;">Generate filter</textarea>
+ </form>
+ <p>(c) William Greenwood 2023</p>
+ </body>
+</html>