샘플링 레이트

Sample rate

초당 소리를 몇 번 측정해 저장할지 정하는 값. 너무 낮으면 원래 없던 가짜 저음(에일리어싱)이 생깁니다.

다른 이름: Sampling rateAliasingNyquist frequency
···
html
<div class="wrap">
  <canvas id="cv"></canvas>
  <div class="cap" id="cap">정상 샘플링</div>
  <button class="play" id="play" type="button" aria-label="play sound"><span class="tri"></span></button>
</div>
css
.wrap{position:relative;width:92%;height:84%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px}
canvas{width:100%;height:68%;display:block}
.cap{font:600 11px/1 monospace;color:var(--muted)}
.play{position:absolute;right:0;bottom:0;width:clamp(28px,15%,40px);aspect-ratio:1;border-radius:50%;border:1px solid var(--line);background:var(--surface);display:grid;place-items:center;cursor:pointer;box-shadow:0 2px 8px rgba(0,0,0,.12)}
.play .tri{width:0;height:0;border-style:solid;border-width:6px 0 6px 9px;border-color:transparent transparent transparent var(--fg);margin-left:2px}
.play:active{transform:scale(.92)}
js
const cv = document.getElementById('cv');
const g2d = cv.getContext('2d');
const cap = document.getElementById('cap');
const cs = getComputedStyle(document.documentElement);
const ACCENT = cs.getPropertyValue('--accent').trim() || '#5b5bf7';
const ACCENT2 = cs.getPropertyValue('--accent-2').trim() || '#f25c8a';
const MUTED = cs.getPropertyValue('--muted').trim() || '#888';
let w, h;
function resize() {
  const dpr = Math.min(devicePixelRatio || 1, 2);
  w = cv.clientWidth; h = cv.clientHeight;
  cv.width = w * dpr; cv.height = h * dpr;
  g2d.setTransform(dpr, 0, 0, dpr, 0, 0);
}
addEventListener('resize', resize);
resize();
function trueWave(x) { return Math.sin(x * Math.PI * 2 * 5.3); }
const CYCLE = 2600;
function draw(t) {
  const p = (t % (CYCLE * 2)) / CYCLE;
  const aliased = p >= 1;
  cap.textContent = aliased ? '언더샘플링 (에일리어싱)' : '정상 샘플링';
  const samples = aliased ? 7 : 34;
  g2d.clearRect(0, 0, w, h);
  const mid = h / 2, amp = h * 0.32;
  g2d.beginPath();
  for (let x = 0; x <= w; x++) {
    const y = mid - trueWave(x / w) * amp;
    if (x === 0) g2d.moveTo(x, y); else g2d.lineTo(x, y);
  }
  g2d.strokeStyle = MUTED;
  g2d.lineWidth = 1;
  g2d.globalAlpha = 0.5;
  g2d.stroke();
  g2d.globalAlpha = 1;
  g2d.beginPath();
  for (let i = 0; i <= samples; i++) {
    const x = (i / samples) * w;
    const y = mid - trueWave(x / w) * amp;
    if (i === 0) g2d.moveTo(x, y); else g2d.lineTo(x, y);
  }
  g2d.strokeStyle = aliased ? ACCENT2 : ACCENT;
  g2d.lineWidth = 2;
  g2d.stroke();
  for (let i = 0; i <= samples; i++) {
    const x = (i / samples) * w;
    const y = mid - trueWave(x / w) * amp;
    g2d.beginPath();
    g2d.arc(x, y, 2.4, 0, Math.PI * 2);
    g2d.fillStyle = aliased ? ACCENT2 : ACCENT;
    g2d.fill();
  }
  requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
function makeHeld(ctx, freq, holdSamples, seconds) {
  const sr = ctx.sampleRate;
  const len = Math.floor(sr * seconds);
  const buf = ctx.createBuffer(1, len, sr);
  const d = buf.getChannelData(0);
  let held = 0;
  for (let i = 0; i < len; i++) {
    if (i % holdSamples === 0) held = Math.sin((2 * Math.PI * freq * i) / sr);
    d[i] = held;
  }
  return buf;
}
document.getElementById('play').addEventListener('click', () => {
  const ctx = new (window.AudioContext || window.webkitAudioContext)();
  const now = ctx.currentTime;
  const clean = makeHeld(ctx, 440, 1, 0.4);
  const aliasedBuf = makeHeld(ctx, 3400, 9, 0.4);
  [clean, aliasedBuf].forEach((buf, i) => {
    const src = ctx.createBufferSource();
    src.buffer = buf;
    const gain = ctx.createGain();
    const t = now + i * 0.45;
    gain.gain.setValueAtTime(0, t);
    gain.gain.linearRampToValueAtTime(0.13, t + 0.01);
    gain.gain.setValueAtTime(0.13, t + 0.36);
    gain.gain.linearRampToValueAtTime(0.0001, t + 0.4);
    src.connect(gain).connect(ctx.destination);
    src.start(t);
  });
  setTimeout(() => ctx.close(), 1200);
});

아날로그(연속적인) 소리를 디지털로 저장하려면 1초에 여러 번 진폭을 측정(샘플링)해야 합니다. CD 음질은 초당 44,100번(44.1kHz), 대부분의 웹 오디오는 44.1~48kHz를 씁니다. 나이퀴스트 정리에 따르면 샘플링 레이트의 절반(나이퀴스트 주파수)보다 높은 주파수는 제대로 기록할 수 없고, 그 대신 실제와 다른 낮은 주파수로 "접혀서(fold back)" 기록됩니다 — 이를 에일리어싱이라 부릅니다.

에일리어싱은 마차 바퀴가 영상에서 거꾸로 도는 것처럼 보이는 착시(스트로보스코프 효과)와 원리가 같습니다 — 측정 간격이 실제 변화 속도를 따라가지 못하면 실제와 다른 패턴이 재구성됩니다. 오디오 엔지니어링에서는 샘플링 전에 나이퀴스트 주파수 이상을 걸러내는 저역통과 필터(안티에일리어싱 필터)로 이를 막습니다. UI/UX 설계자는 보통 샘플레이트를 직접 다루지 않지만, "낮은 비트레이트로 내보낸 알림음이 왜 지지직거리는가"를 설명할 때 이 개념이 필요합니다.

오디오 인코딩·압축의 품질 설정, 저사양 기기용 사운드 자산 최적화, 디지털 신호 처리 전반에 쓰입니다.

언제 쓰나

사운드 자산을 낮은 비트레이트로 압축해야 할 때. 너무 낮추면 원곡에 없던 잡음(에일리어싱)이 들립니다.