here2share

Permutation Music

Jun 4th, 2026 (edited)
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 8.94 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Permutation Music</title>
  7.     <style>
  8.         * {
  9.             margin: 0;
  10.             padding: 0;
  11.             box-sizing: border-box;
  12.         }
  13.         body {
  14.             background: #000;
  15.             color: #0f0;
  16.             font-family: monospace;
  17.             display: flex;
  18.             flex-direction: column;
  19.             align-items: center;
  20.             justify-content: center;
  21.             height: 100vh;
  22.             margin: 0;
  23.             overflow: hidden;
  24.         }
  25.         .container {
  26.             text-align: center;
  27.             background: #111;
  28.             padding: 16px 20px;
  29.             border: 1px solid #0f0;
  30.             border-radius: 4px;
  31.             width: 98vw;
  32.             max-width: 1200px;
  33.         }
  34.         canvas {
  35.             background: #020202;
  36.             border: 1px solid #0f0;
  37.             display: block;
  38.             margin: 0 auto 12px;
  39.             width: 100%;
  40.             height: auto;
  41.             image-rendering: crisp-edges;
  42.         }
  43.         button {
  44.             background: #0f0;
  45.             color: #000;
  46.             border: none;
  47.             padding: 12px 28px;
  48.             font-family: monospace;
  49.             font-weight: bold;
  50.             font-size: 15px;
  51.             cursor: pointer;
  52.             letter-spacing: 1px;
  53.             transition: background 0.15s;
  54.         }
  55.         button:hover {
  56.             background: #0c0;
  57.         }
  58.         .controls {
  59.             margin-top: 12px;
  60.             display: flex;
  61.             flex-direction: column;
  62.             gap: 6px;
  63.             font-size: 13px;
  64.         }
  65.         input[type=range] {
  66.             accent-color: #0f0;
  67.             width: 100%;
  68.             max-width: 360px;
  69.             cursor: pointer;
  70.         }
  71.         label {
  72.             display: flex;
  73.             align-items: center;
  74.             justify-content: center;
  75.             gap: 10px;
  76.         }
  77.     </style>
  78. </head>
  79. <body>
  80. <div class="container">
  81.     <canvas id="c" width="1000" height="260"></canvas>
  82.     <button id="b">START COUNTER</button>
  83.     <div class="controls">
  84.         <label>BPM: <span id="bv">174</span></label>
  85.         <input type="range" id="bs" min="40" max="400" value="174">
  86.         <div>COUNT: <span id="nv">0</span></div>
  87.         <label>VOL: <span id="vv">100</span>%</label>
  88.         <input type="range" id="vs" min="0" max="100" value="100">
  89.     </div>
  90. </div>
  91. <script>
  92.     const c = document.getElementById('c'),
  93.         ctx = c.getContext('2d'),
  94.         b = document.getElementById('b'),
  95.         bs = document.getElementById('bs'),
  96.         bv = document.getElementById('bv'),
  97.         nv = document.getElementById('nv'),
  98.         vs = document.getElementById('vs'),
  99.         vv = document.getElementById('vv');
  100.  
  101.     let W = c.width,
  102.         H = c.height,
  103.         CY = H / 2;
  104.  
  105.     let a = null,
  106.         an = null,
  107.         g = null,
  108.         d = null,
  109.         p = !1,
  110.         bpm = 174,
  111.         s = 0,
  112.         n = 0,
  113.         t = 0,
  114.         tid = null;
  115.  
  116.     const rc = new Float32Array(16),
  117.         ic = new Float32Array(16);
  118.     let ad = new Uint8Array(0);
  119.  
  120.     d = new Float32Array(44100);
  121.     const k = 42,
  122.         deg = Math.PI / 180;
  123.     for (let i = 0; i < 44100; i++) {
  124.        const x = (i * 2) / 44100 - 1;
  125.        d[i] = ((3 + k) * x * 20 * deg) / (Math.PI + k * Math.abs(x));
  126.    }
  127.  
  128.    const MAX_PERM = 12000;
  129.    const permSeq = Array.from({ length: MAX_PERM }, (_, i) => i);
  130.     const popcnt = x => {
  131.         let c = 0;
  132.         while (x) { c += x & 1;
  133.             x >>>= 1; }
  134.         return c;
  135.     };
  136.     permSeq.sort((a, b) => popcnt(a) - popcnt(b) || a - b);
  137.     let permIdx = 0;
  138.  
  139.     function resizeCanvas() {
  140.         const container = c.parentNode;
  141.         const newWidth = Math.min(container.clientWidth - 4, 1200);
  142.         if (newWidth !== W) {
  143.             W = newWidth;
  144.             c.width = W;
  145.             CY = H / 2;
  146.         }
  147.     }
  148.     window.addEventListener('resize', resizeCanvas);
  149.     resizeCanvas();
  150.  
  151.     bs.addEventListener('input', e => { bpm = +e.target.value;
  152.         bv.textContent = bpm; });
  153.     vs.addEventListener('input', e => {
  154.         vv.textContent = e.target.value;
  155.         if (g) g.gain.setValueAtTime(+e.target.value / 100, a.currentTime);
  156.     });
  157.  
  158.     b.addEventListener('click', () => {
  159.         if (!a) {
  160.             a = new(window.AudioContext || window.webkitAudioContext)();
  161.             an = a.createAnalyser();
  162.             an.fftSize = 2048;
  163.             ad = new Uint8Array(an.frequencyBinCount);
  164.             g = a.createGain();
  165.             g.gain.setValueAtTime(+vs.value / 100, a.currentTime);
  166.             g.connect(a.destination);
  167.         }
  168.         if (a.state === 'suspended') a.resume();
  169.         if (p) {
  170.             p = !1;
  171.             b.textContent = 'START COUNTER';
  172.             clearTimeout(tid);
  173.         } else {
  174.             p = !0;
  175.             b.textContent = 'STOP COUNTER';
  176.             t = a.currentTime;
  177.             s = 0;
  178.             sch();
  179.         }
  180.     });
  181.  
  182.     function sch() {
  183.         while (t < a.currentTime + 0.12) {
  184.            q(s, t);
  185.            const st = (60 / bpm) / 2;
  186.            t += st;
  187.            s++;
  188.            if (s >= 8) {
  189.                 s = 0;
  190.                 n = permSeq[permIdx % MAX_PERM];
  191.                 permIdx++;
  192.                 if (permIdx >= MAX_PERM) permIdx = 0;
  193.                 nv.textContent = n;
  194.             }
  195.         }
  196.         tid = setTimeout(sch, 20);
  197.     }
  198.  
  199.     function q(S, T) {
  200.         const p0 = (n ^ (n >> 5) ^ (S * 0x4D)) >>> 0;
  201.         const p1 = ((n * 2654435761) >>> 0) ^ (S << 5);
  202.        const p2 = (n >> (S & 7)) ^ (n << (13 - (S & 7)));
  203.         const m = (p0 >> 3) & 7;
  204.         const isDrum = ((n >> (S & 15)) & 7) === m || ((p1 >> 4) & 7) === (S & 7);
  205.         const baseF = 38 + ((p0 ^ (p0 >> 6)) % 4200);
  206.         const fA = Math.min(6800, Math.max(28, baseF));
  207.         const ratios = [1, 1.006, 1.498, 2.001, 0.499, 0.751, 1.334, 0.667];
  208.         const ri = (p1 >> (S * 3)) & 7;
  209.         const fB = Math.min(7200, Math.max(26, fA * ratios[ri]));
  210.         const dA = isDrum ? 0.025 + ((p2 & 15) * 0.008) : 0.04 + ((p0 >> (S + 2)) & 15) * 0.045;
  211.         const dB = dA * (0.55 + ((p1 >> 6) & 7) * 0.09);
  212.         rc.fill(0);
  213.         ic.fill(0);
  214.         for (let i = 1; i < 16; i++) {
  215.            const b0 = (p0 >> ((i + S) & 15)) & 1;
  216.             const b1 = (p1 >> ((i * 3 + S + 5) & 15)) & 1;
  217.             const b2 = (p2 >> ((i * 2 + S + 11) & 15)) & 1;
  218.             const base = 0.25 / i;
  219.             rc[i] = base + (b0 ? 1.4 / i : 0) + (b1 ? 0.55 / i : 0) + (b2 ? 0.2 / i : 0);
  220.             ic[i] = ((p0 >> ((i + S + 7) & 15)) & 1) ? 0.7 / i : ((p1 >> ((i * 2 + S) & 15)) & 1) ? 0.35 / i : 0;
  221.         }
  222.         const wA = a.createPeriodicWave(rc, ic);
  223.         const wB = a.createPeriodicWave(
  224.             new Float32Array(rc.map((v, i) => v * (0.7 + ((p2 >> i) & 1) * 0.5))),
  225.            new Float32Array(ic.map((v, i) => v * (0.6 + ((p0 >> (i + 3)) & 1) * 0.6)))
  226.        );
  227.         const sh = a.createWaveShaper();
  228.         sh.curve = d;
  229.         sh.oversample = '4x';
  230.         const gA = a.createGain(),
  231.             gB = a.createGain();
  232.         const volA = isDrum ? 0.5 + ((p1 >> 2) & 3) * 0.12 : 0.28 + ((p0 >> 5) & 7) * 0.05;
  233.         const volB = volA * (0.4 + ((p2 >> 3) & 7) * 0.08);
  234.         gA.gain.setValueAtTime(volA, T);
  235.         gA.gain.exponentialRampToValueAtTime(0.0008, T + dA);
  236.         gB.gain.setValueAtTime(volB, T);
  237.         gB.gain.exponentialRampToValueAtTime(0.0006, T + dB);
  238.         const oA = a.createOscillator(),
  239.             oB = a.createOscillator();
  240.         oA.setPeriodicWave(wA);
  241.         oA.frequency.setValueAtTime(fA, T);
  242.         oB.setPeriodicWave(wB);
  243.         oB.frequency.setValueAtTime(fB, T);
  244.         oA.connect(gA);
  245.         oB.connect(gB);
  246.         gA.connect(sh);
  247.         gB.connect(sh);
  248.         sh.connect(an);
  249.         an.connect(g);
  250.         oA.start(T);
  251.         oA.stop(T + dA + 0.02);
  252.         oB.start(T);
  253.         oB.stop(T + dB + 0.02);
  254.     }
  255.  
  256.     function draw() {
  257.         resizeCanvas();
  258.         ctx.clearRect(0, 0, W, H);
  259.         if (p && an && ad.length) {
  260.            an.getByteTimeDomainData(ad);
  261.             ctx.strokeStyle = '#f00';
  262.             ctx.lineWidth = 1;
  263.             ctx.beginPath();
  264.             const len = ad.length;
  265.             for (let i = 0; i < len; i++) {
  266.                const x = (i / (len - 1)) * W;
  267.                const y = (ad[i] / 510) * H * 2;
  268.                if (i === 0) ctx.moveTo(x, y);
  269.                else ctx.lineTo(x, y);
  270.            }
  271.            ctx.stroke();
  272.        } else {
  273.            ctx.strokeStyle = '#0f0';
  274.            ctx.lineWidth = 1;
  275.            ctx.beginPath();
  276.            ctx.moveTo(0, CY);
  277.            ctx.lineTo(W, CY);
  278.            ctx.stroke();
  279.        }
  280.        requestAnimationFrame(draw);
  281.    }
  282.    draw();
  283. </script>
  284. </body>
  285. </html>
Advertisement
Add Comment
Please, Sign In to add comment