diff options
| author | s-ol <s+removethis@s-ol.nu> | 2023-09-02 11:41:09 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2023-09-02 11:41:09 +0000 |
| commit | ee6ca5b32ea7e02a98e7cf5f150636a8d31b60cc (patch) | |
| tree | 50c4be26c87cc73b882a3acdb98f7289ac5a154a | |
| parent | add synthesizer (diff) | |
| download | isomorphic-kb-explorer-ee6ca5b32ea7e02a98e7cf5f150636a8d31b60cc.tar.gz isomorphic-kb-explorer-ee6ca5b32ea7e02a98e7cf5f150636a8d31b60cc.zip | |
| -rw-r--r-- | index.html | 87 | ||||
| -rw-r--r-- | layout.js | 4 | ||||
| -rw-r--r-- | pattern.js | 4 | ||||
| -rw-r--r-- | style.css | 31 | ||||
| -rw-r--r-- | synth.js | 41 |
5 files changed, 121 insertions, 46 deletions
@@ -10,37 +10,58 @@ <canvas id="canvas-bg"></canvas> <canvas id="canvas-fg"></canvas> </main> - <aside class="pattern controls"> - <div class="control control--preset"> - <label for="pattern-preset">pattern</label> - <select id="pattern-preset"> - <option value="custom">(custom)</option> - <optgroup label="scales"> - <option value="major-7" >major</option> - <option value="minor-7" >minor</option> - <option value="minor-harm-7">harmonic minor</option> - <option value="minor-mel-7" >melodic minor</option> - <option value="minor-hung-7">hungarian minor</option> - <option value="penta" >pentatonic</option> - </optgroup> - <optgroup label="triads"> - <option value="major-3" >major</option> - <option value="major-3+">augmented</option> - <option value="minor-3" >minor</option> - <option value="minor-3-">diminished</option> - </optgroup> - </select> - </div> - <div class="control"> - <label for="pattern-len">octave size</label> - <input id="pattern-len" type="number" min="4" value="12" /> - </div> - <div class="steps"> - <input type="checkbox" checked disabled /> - <input type="checkbox" /> - <input type="checkbox" /> - <input type="checkbox" /> - </div> + <aside class="pattern panel"> + <section id="pattern" class="controls"> + <div class="control control--preset"> + <label for="pattern-preset">pattern</label> + <select id="pattern-preset"> + <option value="custom">(custom)</option> + <optgroup label="scales"> + <option value="major-7" >major</option> + <option value="minor-7" >minor</option> + <option value="minor-harm-7">harmonic minor</option> + <option value="minor-mel-7" >melodic minor</option> + <option value="minor-hung-7">hungarian minor</option> + <option value="penta" >pentatonic</option> + </optgroup> + <optgroup label="triads"> + <option value="major-3" >major</option> + <option value="major-3+">augmented</option> + <option value="minor-3" >minor</option> + <option value="minor-3-">diminished</option> + </optgroup> + </select> + </div> + <div class="control"> + <label for="pattern-len">octave size</label> + <input id="pattern-len" type="number" min="4" value="12" /> + </div> + <div class="steps"> + <input type="checkbox" checked disabled /> + <input type="checkbox" /> + <input type="checkbox" /> + <input type="checkbox" /> + </div> + </section> + <section id="synth" class="controls"> + <div class="control control--toggle"> + <label for="synth-enabled">synth</label> + <input id="synth-enabled" type="checkbox" checked /> + </div> + <div class="control"> + <label for="synth-freq">center freq</label> + <input id="synth-freq" type="number" min="0" value="110" /> + </div> + <div class="control"> + <label for="synth-voices">voices</label> + <input id="synth-voices" type="number" min="1" max="32" value="8" /> + </div> + <div class="control control--toggle"> + <label><a href="synth.html" target="_blank">options</a></label> + <button id="synth-opts-paste">paste</button> + <button id="synth-opts-reset">reset</button> + </div> + </section> </aside> <aside class="layout"> <svg @@ -97,7 +118,7 @@ id="turn-cw" class="turn" transform="rotate(1.5)" d="M 63.875 -112.84961 L 59.068359 -104.08203 C 69.570355 -98.323686 70.491716 -97.891327 78.669922 -89.982422 L 74.099609 -85.28125 L 96.498047 -79.628906 L 95.910156 -81.712891 L 90.216797 -101.85938 L 85.628906 -97.140625 C 76.875667 -105.51066 74.458477 -107.04659 63.875 -112.84961 z " /> </svg> - <div class="controls"> + <section id="layout" class="panel controls"> <div class="control control--preset"> <label for="layout-preset">layout</label> <select id="layout-preset"> @@ -132,7 +153,7 @@ invert </label> </div> - </div> + </section> </aside> <script type="module" src="main.js"></script> </body> @@ -1,9 +1,9 @@ -const panel = document.querySelector('aside.layout'); +const panel = document.getElementById('layout'); const svg = document.getElementById('diagram'); const arrows = Array.from(svg.querySelectorAll('.arrow')); -const preset = panel.querySelector('.control--preset select'); +const preset = document.getElementById('layout-preset'); const controls = Array.from(panel.querySelectorAll('.control--axis')); const steps = Array.from(panel.querySelectorAll('.control--axis > input')); const dirs = Array.from(panel.querySelectorAll('.control--axis .dir input')); @@ -1,6 +1,6 @@ -const panel = document.querySelector('aside.pattern'); +const panel = document.getElementById('pattern'); -const preset = panel.querySelector('.control--preset select'); +const preset = document.getElementById('pattern-preset'); const patternLength = document.getElementById('pattern-len'); const steps = panel.querySelector('.steps'); @@ -54,15 +54,35 @@ aside.layout > svg { height: 100%; } -.controls { +.panel { display: flex; flex-direction: column; - justify-content: center; + gap: 0.75rem; padding: 1rem 1.5rem; - gap: 0.25rem; background: #eeeeee; } +.panel section + section { + padding-top: 0.3rem; + border-top: 1px solid #b9bdc1; +} + +.controls { + display: flex; + flex-direction: column; + justify-content: flex-start; + overflow: hidden; + gap: 0.25rem; +} + +.controls--minimized { + max-height: 1.25em; +} + +#layout.controls { + justify-content: center; +} + /* controls */ .control { display: flex; @@ -77,8 +97,6 @@ aside.layout > svg { } .control--preset { - padding-bottom: 0.5rem; - border-bottom: 1px solid #b9bdc1; margin-bottom: 0.25rem; } @@ -86,10 +104,11 @@ aside.layout > svg { flex: 1; } -.control--preset label:first-child { +.controls .control:first-child label:first-child { font-weight: bold; } +.control--toggle label:first-child, .control--axis label:first-child { flex: 1; } @@ -1,6 +1,13 @@ import SimpleJSSynth from './simple-js-synth.js'; import * as pattern from './pattern.js'; +const panel = document.getElementById('synth'); +const enabled = document.getElementById('synth-enabled'); +const freq = document.getElementById('synth-freq'); +const poly = document.getElementById('synth-voices'); +const optsPaste = document.getElementById('synth-opts-paste'); +const optsReset = document.getElementById('synth-opts-reset'); + const ctx = new window.AudioContext(); const opts = {}; @@ -19,23 +26,51 @@ export const setOptions = (o) => { voices.push(SimpleJSSynth(ctx.destination, opts)); }; -setOptions({ +enabled.onchange = () => { + if (enabled.checked) ctx.resume(); + else ctx.suspend(); + + panel.classList.toggle('controls--minimized', !enabled.checked); +}; + +freq.onchange = () => { + let frequency = +freq.value; + if (!frequency || frequency < 1) frequency = 110; + opts.frequency = frequency; +}; + +poly.onchange = () => { + let polyphony = +poly.value; + if (!polyphony || polyphony < 1) polyphony = 1; + setOptions({ polyphony }); +}; + +optsPaste.onclick = () => { + const json = window.prompt("Please paste the JSON from the right panel of the synth page:"); + setOptions(JSON.parse(json)); +}; + +optsReset.onclick = () => setOptions({ osc1type: "sine", osc1vol: 0.2, osc1tune: 0, osc2type: "square", osc2vol: 0.14, osc2tune: 12, osc3type: "sine", osc3vol: 0.05, osc3tune: -6.7, attack: 0, decay: 0.3, sustain: 0.5, susdecay: 5, cutoff: 36, + frequency: 110, polyphony: 8, }); +optsReset.onclick(); + export const on = (key, note, vol=1) => { - ctx.resume() + if (!enabled.checked) return; + ctx.resume(); if (tones[key]?.note === note) return; off(key); - const freq = 110.0 * Math.pow(2, note / pattern.getLength()); + const freq = opts.frequency * Math.pow(2, note / pattern.getLength()); const voice = voices.find(s => s.isReady()); if (!voice) return; |
