<!-- SS · part 23 -->
otes) { var len = 1; for (var k = step + 1; k < STEPS && !P.chords[k]; k++) len++; E.inst.chords.triggerAttackRelease(notes, Tone.Time('16n').toSeconds() * Math.min(len, 8), time, 0.6); } }
      var l = P.lead[step]; if (l) E.inst.lead.triggerAttackRelease(l, '16n', time, 0.7);
      var bar = E.bar;
      Tone.getDraw().schedule(function () { drawPlayhead(step, bar); }, time);
    }, idx, '16n');
    E.seq.start(0);
    return E;
  }
  function setSound(track, kind) {
    S.sounds[track] = kind; save();
    if (!E) return;
    if (E.inst[track]) { try { E.inst[track].releaseAll && E.inst[track].releaseAll(); } catch (e) {} try { E.inst[track].dispose(); } catch (e) {} }
    E.inst[track] = track === 'drums' ? makeDrums(kind, E.ch.drums) : makeSynth(track, kind, E.ch[track]);
  }
  var playing = false;
  function checkUnlock() {
    var need = !window.Tone || Tone.getContext().state !== 'running';
    $('#ss-unlock').hidden = !need;
  }
  function unlock() {
    if (!window.Tone) return Promise.reject(new Error('no Tone'));
    return Tone.start().then(function () { buildEngine(); checkUnlock(); });
  }
  $('#ss-unlock-btn').addEventListener('click', function () { unlock().then(function () { toast('Sound is on.'); }, function () { toast('Could not start audio.'); }); });
  function start() {
    return unlock().then(function () {
      var T = E.T; T.stop(); T.position = 0; E.bar = 0; E.started = false;
      scheduleVox();
      T.start('+0.08'); playing = true; setPlayButtons();
    });
  }
  function stop() {
    if (!E) return; E.T.stop(); playing = false; setPlayButtons(); drawPlayhead(-1, 0);
  }
  function setPlayButtons() {
    $('#ss-play').textContent = playing ? '■ Stop' : '▶ Play';
    $('#ss-vplay').textContent = playing ? '■ Stop' : '▶ Play with beat';
  }
  $('#ss-play').addEventListener('click', function () { if (playing) stop(); else start().catch(function () { toast('Tap again to start audio.'); }); });
  $('#ss-vplay').addEventListener('click', function () {
    if (playing) return stop();
    if (!S.voxClips || !S.voxClips.length) toast('No vocals rendered yet — playing the beat.');
    start().catch(function () { toast('Tap again to start audio.'); });
  });
  var lastCol = -1;
  function drawPlayhead(step, bar) {
    if (lastCol >= 0) $$('.ss-step[data-i="' + lastCol + '"]').forEach(function (c) { c.classList.remove('now'); });
    lastCol = step;
    if (step >= 0) { $$('.ss-step[data-i="' + step + '"]').forEach(function (c) { c.classList.add('now'); }); $('#ss-pos').textContent = 'bar ' + (bar + 1); }
    else $('#ss-pos').textContent = 'bar 1';
  }

  // ---------------------------------------------------------------- STUDIO UI
  var keySel = $('#ss-key'); keySel.innerHTML = KEYS.map(function (k) { return '<option>' + k + '</option>'; }).join('');
  function penOptions(track) {
    if (track === 'bass') return scaleNotes(S.key, [1, 2]).concat([]);
    if (track === 'lead') return scaleNotes(S.key, [4, 5]);
    var ch = (S.chords || []).slice(); diatonicChords(S.key).forEach(function (c) { if (ch.indexOf(c) < 0) ch.push(c); }); return ch;
  }
  var TRACKS = [['drums', 'Drums'], ['bass', 'Bass'], ['chords', 'Chords'], ['lead', 'Lead']];
  function stepBtn(i, on, label) { return '<button type="button" class="ss-step' + (on ? ' on' : '') + (i % 4 === 0 ? ' q' : '') + '" data-i="' + i + '" aria-label="step ' + (i + 1) + '">' + esc(label || '') + '</button>'; }
  function renderTracks() {
    var html = TRACKS.map(function (t) {
      var id = t[0], P = S.patterns;
      var head = '<div class="ss-thead"><span class="ss-tname">' + t[1] + '</span>' +
        '<select class="ss-input ss-sel" data-snd="' + id + '" aria-label="' + t[1] + ' sound">' + SOUNDS[id].map(function (s) { return '<option' + (S.sounds[id] === s ? ' selected' : '') + '>' + s + '</option>'; }).join('') + '</select>' +
        '<input type="range" min="-36" max="6" step="1" value="' + S.vols[id] + '" data-vol="' + id + '" aria-label="' + t[1] + ' volume">' +
        '<button type="button" class="ss-btn ss-btn-sm ss-mute' + (S.mutes[id] ? ' is-on' : '') + '" data-mute="' + id + '">M</button>' +
        '<button type="button" class="ss-btn ss-btn-sm" data-regen="' + id + '">↻ AI</button></div>';
      var body = '';
      if (id === 'drums') {
        ['kick', 'snare', 'hat'].forEach(function (r) {
          body += '<div class="ss-rowlbl">' + r + '</div><div class="ss-grid" data-track="drums" data-row="' + r + '">';
          for (var i = 0; i < STEPS; i++) body += stepBtn(i, P.drums[r][i]);
          body += '</div>';
        });
      } else {
        var opts = penOptions(id); if (!S.pens[id] || opts.indexOf(S.pens[id]) < 0) S.pens[id] = opts[0];
        body += '<div class="ss-pen">Tap a step to place <select class="ss-input ss-sel" data-pen="' + id + '">' + opts.map(function (o) { return '<option' + (o === S.pens[id] ? ' selected' : '') + '>' + o + '</option>'; }).join('') + '</select></div>'