창의개인연구

창의개인연구 ② PannerNode와 Three.js로 만든 첫 공간 음향 데모

2
창의개인연구 ② PannerNode와 Three.js로 만든 첫 공간 음향 데모

창의개인연구 시리즈. 이론을 정리한 ① 글에 이어, 처음으로 작동하는 공간 음향 데모를 만든다.

목표: "소리가 그쪽에서 난다"를 직접 듣기

이 단계의 목표는 단 하나다. 헤드폰을 끼고 화면 위의 점을 움직였을 때, 그 점의 방향에서 소리가 들리는 것을 청감으로 확인하는 것. 알고리즘 검증보다도 "지금 가는 방향이 맞다"는 감각적 근거를 빨리 잡고 싶었다.

그래서 구성을 최소로 잡았다.

  • 소리 합성: OscillatorNode로 단순한 사인파.
  • 공간화: PannerNode(HRTF 모드)로 위치 기반 좌우·앞뒤 감각 부여.
  • 시각화: Three.js로 3D 씬을 띄우고, 소리의 위치를 빨간 구체로 표시.

PannerNodepositionX/Y/Z를 마우스 좌표와 연동하면, 시각적 위치와 청각적 위치가 동시에 움직인다. 입력과 결과가 같은 좌표계 위에 올라간다는 점에서 디버깅하기에도 편하다.

PannerNode를 HRTF로 쓰는 이유

PannerNode에는 panningModel 옵션이 있다. 기본값은 equalpower인데, 이건 좌우 채널의 볼륨 비율만 조정하는 단순 패닝이다. 정면에 두든 뒤에 두든 결과가 비슷해서, "방향성"이라는 본 연구 목적에는 부족하다.

반면 panningModel = "HRTF"로 두면 브라우저 엔진이 내장 HRTF 임펄스 응답을 적용해 좌우뿐 아니라 상하·앞뒤도 어느 정도 재현한다. 데모 코드는 별도 라이브러리 없이 다음만 있으면 동작했다.

const ctx = new AudioContext();
const osc = ctx.createOscillator();
const panner = ctx.createPanner();
panner.panningModel = "HRTF";
panner.distanceModel = "inverse";
osc.connect(panner).connect(ctx.destination);
osc.start();
 
function setPos(x, y, z) {
  const t = ctx.currentTime;
  panner.positionX.setValueAtTime(x, t);
  panner.positionY.setValueAtTime(y, t);
  panner.positionZ.setValueAtTime(z, t);
}

distanceModel은 일단 inverse로 둬서, 멀어질수록 부드럽게 감쇠하도록 했다. 거리 모델 세 종류의 차이는 다음 글(③)에서 따로 다룬다.

Three.js로 위치 보여주기

소리만 듣고 있으면 "지금 어디에 두었나"를 머릿속으로 추적하기 어렵다. 시각화가 필요했다. Three.js의 Scene, PerspectiveCamera, WebGLRenderer 조합으로 가장 단순한 3D 무대를 만들고, 가운데에 청자(노란 구), 마우스가 가리키는 위치에 음원(빨간 구)을 두었다.

마우스 좌표를 3D 공간 좌표로 변환할 때는 정확도보다 직관성을 우선시했다. 카메라가 바라보는 평면 위에 마우스 포인터를 투영하고, 그 좌표를 PannerNode의 위치에 그대로 전달했다. "마우스를 오른쪽 위로 옮기면 오른쪽 위에서 소리가 난다"는 일대일 매핑이 잘 작동했다.

직접 들어 본 결과

헤드폰 기준으로,

  • 좌우는 매우 명확하다. 마우스를 왼쪽 끝과 오른쪽 끝으로 옮기면 청자의 좌우에서 또렷이 들린다.
  • 앞뒤는 미묘하다. 음원이 정면일 때와 뒤편일 때를 같은 음으로 비교하면 구분이 어렵다. HRTF의 한계 중 잘 알려진 front-back confusion 이다.
  • 상하는 거의 안 들린다. Y축 변화는 거의 인지되지 않았다. 마찬가지로 일반화된 HRTF의 알려진 약점.

좌우가 잘 들리는 것만으로도 "공간 음향이 작동한다"고 말하기에 충분했다. 이 데모를 만든 시점부터, 연구의 다음 질문이 "어떻게 더 잘 들리게 만드는가"로 자연스럽게 옮겨갔다.

한계

이번 데모에는 문제도 많았다.

  • Three.js 모듈 로딩이 불안정해서 빌드 환경에 따라 자주 깨졌다.
  • 소리의 강약·원근감을 더 정교하게 조절하고 싶다. 거리 모델 비교가 필요하다.
  • 사용자가 머리를 돌리면 음원의 방향도 그에 맞춰 갱신되어야 진짜 보조 장치다. 자이로/IMU 연동이 미래의 숙제로 남았다.

관련 글