diff --git a/js/api.js b/js/api.js index edd5631..74bbd0a 100644 --- a/js/api.js +++ b/js/api.js @@ -1724,24 +1724,37 @@ async function adminGamGetUser(id) { return req('GET', `/gamifi master.gain.value = 0.16; const comp = ctx.createDynamicsCompressor(); // мягкий лимитер от перегруза master.connect(comp); comp.connect(ctx.destination); - // Нисходящий перезвон (Вестминстер-lite): E5 · D5 · C5 · G4 — «бим-бам-бом-бо-о-ом» - const notes = [659.25, 587.33, 523.25, 392.00]; - const step = 0.30; - notes.forEach((freq, i) => { - const start = t0 + i * step; - const dur = (i === notes.length - 1) ? 1.7 : 0.95; // последняя нота длиннее - // Колоколообразный тембр: основной тон + обертоны, экспон. затухание - [[1, 0.5], [2, 0.16], [3, 0.06]].forEach(([mult, amp]) => { - const osc = ctx.createOscillator(); - const g = ctx.createGain(); - osc.type = 'sine'; - osc.frequency.value = freq * mult; - g.gain.setValueAtTime(0.0001, start); - g.gain.exponentialRampToValueAtTime(amp, start + 0.012); - g.gain.exponentialRampToValueAtTime(0.0001, start + dur); - osc.connect(g); g.connect(master); - osc.start(start); - osc.stop(start + dur + 0.05); + // Полный вестминстерский бой (школьно-часовой перезвон) — 5 фраз по 4 ноты + // на нотах G4 · C5 · D5 · E5. Узнаваемый «вызов на урок». + const G4 = 392.00, C5 = 523.25, D5 = 587.33, E5 = 659.25; + const PHRASES = [ + [E5, D5, C5, G4], + [C5, E5, D5, G4], + [C5, D5, E5, C5], + [E5, C5, D5, G4], + [G4, D5, E5, C5], + ]; + const step = 0.32, gap = 0.22; // шаг между нотами и пауза между фразами + let t = t0; + PHRASES.forEach((ph, pi) => { + ph.forEach((freq, ni) => { + const lastOfPhrase = ni === ph.length - 1; + const lastOverall = pi === PHRASES.length - 1 && lastOfPhrase; + const dur = lastOverall ? 2.2 : (lastOfPhrase ? 1.2 : 0.9); // концы фраз длиннее + // Колоколообразный тембр: основной тон + обертоны, экспон. затухание + [[1, 0.5], [2, 0.16], [3, 0.06]].forEach(([mult, amp]) => { + const osc = ctx.createOscillator(); + const g = ctx.createGain(); + osc.type = 'sine'; + osc.frequency.value = freq * mult; + g.gain.setValueAtTime(0.0001, t); + g.gain.exponentialRampToValueAtTime(amp, t + 0.012); + g.gain.exponentialRampToValueAtTime(0.0001, t + dur); + osc.connect(g); g.connect(master); + osc.start(t); + osc.stop(t + dur + 0.05); + }); + t += step + (lastOfPhrase ? gap : 0); }); }); } catch {}