User:Pailiaq/common.js: Difference between revisions

Pailiaq (talk | contribs)
No edit summary
Pailiaq (talk | contribs)
No edit summary
Line 5: Line 5:
     var activeNodes = [];
     var activeNodes = [];
     var activeBtn = null;
     var activeBtn = null;
    var STORAGE_KEY = 'edoChordPlayTimbre';
    var TIMBRES = ['triangle', 'sawtooth', 'square', 'sine'];
    var TIMBRE_LABELS = { triangle: 'Triangle', sawtooth: 'Sawtooth', square: 'Square', sine: 'Sine' };
    var timbre = (function () {
        try {
            var saved = localStorage.getItem(STORAGE_KEY);
            return TIMBRES.indexOf(saved) >= 0 ? saved : 'triangle';
        } catch (e) { return 'triangle'; }
    })();
    function setTimbre(t) {
        if (TIMBRES.indexOf(t) < 0) return;
        timbre = t;
        try { localStorage.setItem(STORAGE_KEY, t); } catch (e) {}
        // Keep every selector on the page in sync
        document.querySelectorAll('.edo-chord-timbre').forEach(function (sel) {
            sel.value = t;
        });
    }


     function getCtx() {
     function getCtx() {
Line 31: Line 51:
         if (c.state === 'suspended') c.resume();
         if (c.state === 'suspended') c.resume();
         var now = c.currentTime;
         var now = c.currentTime;
         var base = 261.63;                 // middle C
         var base = 261.63;
         var attack = 0.1, sustain = 0.15, release = 4;
         var attack = 0.02, sustain = 2.5, release = 1.5;
         var totalDur = attack + sustain + release;
         var totalDur = attack + sustain + release;
         var peak = 0.18 / Math.sqrt(centsArr.length);
         var peak = 0.18 / Math.sqrt(centsArr.length);
Line 39: Line 59:
             var osc = c.createOscillator();
             var osc = c.createOscillator();
             var gain = c.createGain();
             var gain = c.createGain();
             osc.type = 'triangle';
             osc.type = timbre;
             osc.frequency.value = base * Math.pow(2, cents / 1200);
             osc.frequency.value = base * Math.pow(2, cents / 1200);
             gain.gain.setValueAtTime(0, now);
             gain.gain.setValueAtTime(0, now);
Line 58: Line 78:
             }, totalDur * 1000);
             }, totalDur * 1000);
         }
         }
    }
    function injectSelectors() {
        var tables = new Set();
        document.querySelectorAll('.edo-chord-play').forEach(function (btn) {
            var table = btn.closest('table');
            if (table) tables.add(table);
        });
        tables.forEach(function (table) {
            var firstTh = table.querySelector('th');
            if (!firstTh || firstTh.querySelector('.edo-chord-timbre')) return;
            var sel = document.createElement('select');
            sel.className = 'edo-chord-timbre';
            sel.title = 'Synth timbre';
            TIMBRES.forEach(function (t) {
                var opt = document.createElement('option');
                opt.value = t;
                opt.textContent = TIMBRE_LABELS[t];
                if (t === timbre) opt.selected = true;
                sel.appendChild(opt);
            });
            sel.addEventListener('change', function () { setTimbre(sel.value); });
            sel.addEventListener('click', function (e) { e.stopPropagation(); });
            firstTh.innerHTML = '';
            firstTh.appendChild(sel);
        });
     }
     }


Line 64: Line 110:
         if (!btn) return;
         if (!btn) return;
         e.preventDefault();
         e.preventDefault();
         if (btn === activeBtn) { stopAll(); return; }   // click again to stop
         if (btn === activeBtn) { stopAll(); return; }
         var edo = parseInt(btn.dataset.edo, 10);
         var edo = parseInt(btn.dataset.edo, 10);
         var steps = (btn.dataset.steps || '').split(',').map(Number);
         var steps = (btn.dataset.steps || '').split(',').map(Number);
Line 78: Line 124:
         }
         }
     });
     });
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', injectSelectors);
    } else {
        injectSelectors();
    }
}());
}());