git.s-ol.nu isomorphic-kb-explorer / main
add synth panel s-ol 24 days ago
5 changed file(s) with 121 addition(s) and 46 deletion(s). Raw diff Collapse all Expand all
99 <canvas id="canvas-bg"></canvas>
1010 <canvas id="canvas-fg"></canvas>
1111 </main>
12 <aside class="pattern controls">
13 <div class="control control--preset">
14 <label for="pattern-preset">pattern</label>
15 <select id="pattern-preset">
16 <option value="custom">(custom)</option>
17 <optgroup label="scales">
18 <option value="major-7" >major</option>
19 <option value="minor-7" >minor</option>
20 <option value="minor-harm-7">harmonic minor</option>
21 <option value="minor-mel-7" >melodic minor</option>
22 <option value="minor-hung-7">hungarian minor</option>
23 <option value="penta" >pentatonic</option>
24 </optgroup>
25 <optgroup label="triads">
26 <option value="major-3" >major</option>
27 <option value="major-3+">augmented</option>
28 <option value="minor-3" >minor</option>
29 <option value="minor-3-">diminished</option>
30 </optgroup>
31 </select>
32 </div>
33 <div class="control">
34 <label for="pattern-len">octave size</label>
35 <input id="pattern-len" type="number" min="4" value="12" />
36 </div>
37 <div class="steps">
38 <input type="checkbox" checked disabled />
39 <input type="checkbox" />
40 <input type="checkbox" />
41 <input type="checkbox" />
42 </div>
12 <aside class="pattern panel">
13 <section id="pattern" class="controls">
14 <div class="control control--preset">
15 <label for="pattern-preset">pattern</label>
16 <select id="pattern-preset">
17 <option value="custom">(custom)</option>
18 <optgroup label="scales">
19 <option value="major-7" >major</option>
20 <option value="minor-7" >minor</option>
21 <option value="minor-harm-7">harmonic minor</option>
22 <option value="minor-mel-7" >melodic minor</option>
23 <option value="minor-hung-7">hungarian minor</option>
24 <option value="penta" >pentatonic</option>
25 </optgroup>
26 <optgroup label="triads">
27 <option value="major-3" >major</option>
28 <option value="major-3+">augmented</option>
29 <option value="minor-3" >minor</option>
30 <option value="minor-3-">diminished</option>
31 </optgroup>
32 </select>
33 </div>
34 <div class="control">
35 <label for="pattern-len">octave size</label>
36 <input id="pattern-len" type="number" min="4" value="12" />
37 </div>
38 <div class="steps">
39 <input type="checkbox" checked disabled />
40 <input type="checkbox" />
41 <input type="checkbox" />
42 <input type="checkbox" />
43 </div>
44 </section>
45 <section id="synth" class="controls">
46 <div class="control control--toggle">
47 <label for="synth-enabled">synth</label>
48 <input id="synth-enabled" type="checkbox" checked />
49 </div>
50 <div class="control">
51 <label for="synth-freq">center freq</label>
52 <input id="synth-freq" type="number" min="0" value="110" />
53 </div>
54 <div class="control">
55 <label for="synth-voices">voices</label>
56 <input id="synth-voices" type="number" min="1" max="32" value="8" />
57 </div>
58 <div class="control control--toggle">
59 <label><a href="synth.html" target="_blank">options</a></label>
60 <button id="synth-opts-paste">paste</button>
61 <button id="synth-opts-reset">reset</button>
62 </div>
63 </section>
4364 </aside>
4465 <aside class="layout">
4566 <svg
96117 id="turn-cw" class="turn" transform="rotate(1.5)"
97118 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 " />
98119 </svg>
99 <div class="controls">
120 <section id="layout" class="panel controls">
100121 <div class="control control--preset">
101122 <label for="layout-preset">layout</label>
102123 <select id="layout-preset">
131152 invert
132153 </label>
133154 </div>
134 </div>
155 </section>
135156 </aside>
136157 <script type="module" src="main.js"></script>
137158 </body>
0 const panel = document.querySelector('aside.layout');
0 const panel = document.getElementById('layout');
11
22 const svg = document.getElementById('diagram');
33 const arrows = Array.from(svg.querySelectorAll('.arrow'));
44
5 const preset = panel.querySelector('.control--preset select');
5 const preset = document.getElementById('layout-preset');
66 const controls = Array.from(panel.querySelectorAll('.control--axis'));
77 const steps = Array.from(panel.querySelectorAll('.control--axis > input'));
88 const dirs = Array.from(panel.querySelectorAll('.control--axis .dir input'));
0 const panel = document.querySelector('aside.pattern');
0 const panel = document.getElementById('pattern');
11
2 const preset = panel.querySelector('.control--preset select');
2 const preset = document.getElementById('pattern-preset');
33 const patternLength = document.getElementById('pattern-len');
44 const steps = panel.querySelector('.steps');
55
5353 height: 100%;
5454 }
5555
56 .panel {
57 display: flex;
58 flex-direction: column;
59 gap: 0.75rem;
60 padding: 1rem 1.5rem;
61 background: #eeeeee;
62 }
63
64 .panel section + section {
65 padding-top: 0.3rem;
66 border-top: 1px solid #b9bdc1;
67 }
68
5669 .controls {
5770 display: flex;
5871 flex-direction: column;
72 justify-content: flex-start;
73 overflow: hidden;
74 gap: 0.25rem;
75 }
76
77 .controls--minimized {
78 max-height: 1.25em;
79 }
80
81 #layout.controls {
5982 justify-content: center;
60 padding: 1rem 1.5rem;
61 gap: 0.25rem;
62 background: #eeeeee;
6383 }
6484
6585 /* controls */
7696 }
7797
7898 .control--preset {
79 padding-bottom: 0.5rem;
80 border-bottom: 1px solid #b9bdc1;
8199 margin-bottom: 0.25rem;
82100 }
83101
85103 flex: 1;
86104 }
87105
88 .control--preset label:first-child {
106 .controls .control:first-child label:first-child {
89107 font-weight: bold;
90108 }
91109
110 .control--toggle label:first-child,
92111 .control--axis label:first-child {
93112 flex: 1;
94113 }
00 import SimpleJSSynth from './simple-js-synth.js';
11 import * as pattern from './pattern.js';
2
3 const panel = document.getElementById('synth');
4 const enabled = document.getElementById('synth-enabled');
5 const freq = document.getElementById('synth-freq');
6 const poly = document.getElementById('synth-voices');
7 const optsPaste = document.getElementById('synth-opts-paste');
8 const optsReset = document.getElementById('synth-opts-reset');
29
310 const ctx = new window.AudioContext();
411
1825 voices.push(SimpleJSSynth(ctx.destination, opts));
1926 };
2027
21 setOptions({
28 enabled.onchange = () => {
29 if (enabled.checked) ctx.resume();
30 else ctx.suspend();
31
32 panel.classList.toggle('controls--minimized', !enabled.checked);
33 };
34
35 freq.onchange = () => {
36 let frequency = +freq.value;
37 if (!frequency || frequency < 1) frequency = 110;
38 opts.frequency = frequency;
39 };
40
41 poly.onchange = () => {
42 let polyphony = +poly.value;
43 if (!polyphony || polyphony < 1) polyphony = 1;
44 setOptions({ polyphony });
45 };
46
47 optsPaste.onclick = () => {
48 const json = window.prompt("Please paste the JSON from the right panel of the synth page:");
49 setOptions(JSON.parse(json));
50 };
51
52 optsReset.onclick = () => setOptions({
2253 osc1type: "sine", osc1vol: 0.2, osc1tune: 0,
2354 osc2type: "square", osc2vol: 0.14, osc2tune: 12,
2455 osc3type: "sine", osc3vol: 0.05, osc3tune: -6.7,
2556 attack: 0, decay: 0.3, sustain: 0.5, susdecay: 5,
2657 cutoff: 36,
2758
59 frequency: 110,
2860 polyphony: 8,
2961 });
3062
63 optsReset.onclick();
64
3165 export const on = (key, note, vol=1) => {
32 ctx.resume()
66 if (!enabled.checked) return;
67 ctx.resume();
3368
3469 if (tones[key]?.note === note) return;
3570 off(key);
3671
37 const freq = 110.0 * Math.pow(2, note / pattern.getLength());
72 const freq = opts.frequency * Math.pow(2, note / pattern.getLength());
3873
3974 const voice = voices.find(s => s.isReady());
4075 if (!voice) return;