에어 테레민 제작기
MediaPipe Hands 트래킹 기반 2.5D 비접촉 가상 신디사이저 악기

카메라 연결 대기 및 악기 보정 가이드 화면
에어 테레민 (AcousticSynth V2) 제작기
웹캠 손동작 컴퓨터 비전 트래킹과 웹 오디오 신호 처리(Web Audio DSP) 기술로 탄생한 무접촉 2.5D 가상 공간 악기
1. 문제 정의 및 기획 배경
테레민 연주 영상을 보고 독특한 연주 방식과 신비로운 음색에 매료되어 직접 연주해보고 싶었으나, 전용 하드웨어 악기 자체의 가격이 너무 비싸 아쉬움을 느끼고 있었습니다. 그러던 중 별도의 특수 센서 없이 일반 노트북에 탑재된 웹캠 하나와 인공지능 자세 인식 기술만 결합하면 허공의 좌표를 악기처럼 연주할 수 있지 않을까 하는 영감이 떠올랐습니다. 특히 MediaPipe의 손가락 마디 인식 기술이 의외로 매우 정교하고 반응 속도가 빠르다는 점에 착안하여, 웹 브라우저에서 비용 제로로 연주 가능한 가상 공간 무접촉 악기 개발에 착수하게 되었습니다.
2. 핵심 사양 및 구현 목표
- 무접촉 연주 사용자 경험(UX) 구현: 센서 없이 웹캠 비디오 입력만으로 양손의 21개 랜드마크 분석 및 실시간 연동.
- 프로급 오디오 품질 확보: 브라우저 표준 Web Audio API를 활용해 노이즈와 디지털 찢어짐(Clipping)이 없는 깨끗하고 풍성한 아날로그 사운드 합성.
- 실시간 인터랙티브 시각화: 연주 주파수 및 볼륨 데이터를 실시간으로 피드백하는 2.5D 캔버스 네온 스킨 및 오실로스코프 그래픽 구현.
- 핵심 기술 스택:
- Frontend: React, TypeScript, Tailwind CSS, Vite
- Computer Vision: MediaPipe Hands (
@mediapipe/hands), Canvas 2D Renderer - Audio DSP Engine: Native Web Audio API (OscillatorNode, BiquadFilterNode, ConvolverNode, DynamicsCompressorNode)
3. 기술 검증 및 트러블슈팅
[1단계] 손가락 트래킹 및 좌표 필터링 설계
MediaPipe Hands의 랜드마크 중 검지 끝과 엄지 끝의 거리(볼륨) 및 손끝 좌표(음정)를 추적하여 오디오 엔진의 입력 변수로 노멀라이징하는 파서를 제작했습니다.
[2단계] Web Audio DSP 사운드 체인 구축
듀얼 오실레이터 보이스(기음 + 배음)를 믹싱하고 로우패스 필터, 딜레이 피드백 루프, 무네트워크 리버브 컨볼버 노드를 순차 결합하여 음을 풍부하게 만드는 사운드 회로를 빌드했습니다.
[3단계] 이중 손동작 매핑 구현
오른손의 가로 위치는 피치(마호가니 건반 영역), 주먹 쥠 정도는 마스터 볼륨에 매핑하고, 왼손의 세로 위치는 필터 컷오프, 깊이(Z축 거리)는 잔향 및 공간감(Reverb & Delay)에 매핑시켰습니다.
R&D 및 트러블슈팅
1. 손을 공중에서 이동할 때 발생하는 반음계 경계 Snap Lag
- 문제: 음계 건반의 경계 영역(예: 솔과 라 사이)에서 손가락이 미세하게 떨릴 때, 주파수 값이 경계를 넘나들며 심한 Snap Lag 현상과 노이즈가 발생했습니다.
- 해결: 음계 폭의 15% 크기를 갖는 동적 이력 현상 버퍼(Hysteresis Buffer)를 경계 검사에 주입하여, 경계를 완전히 넘어가기 전까지는 이전 음정을 강하게 홀딩하도록 슈미트 트리거와 유사한 논리를 설계하여 고음역 연주 오차를 해결했습니다.
2. 공간 이펙터 조율 시 발생하는 Loudness Spike
- 문제: 연주자가 왼손의 Z축 깊이를 조작하여 리버브 Gain을 끌어올릴 때, 공간음과 원음이 급격히 합산되며 전체 성량이 순간적으로 튀어 오르는 오디오 피크 문제가 발생했습니다.
- 해결: 전체 에너지를 평탄화하기 위해 상호 보완 크로스페이드(Crossfade) 방식을 채택했습니다. 리버브 신호(Wet) 볼륨을 높일 때 원음(Dry) 볼륨을 반비례적으로 감쇄(
1.0 - mix * 0.25)시키는 보간 수식을 이식하여 전체 성량을 균일하게 고정했습니다.
4. 핵심 기능 및 구현 코드
- 듀얼 오실레이터 보이스 모핑 (Dual-Oscillator Voice Morphing): 맑고 뚜렷한 Sine파(기음 80
90%)와 따뜻하고 두터운 Triangle파(배음 1020%)를 실시간 크로스페이드 믹싱하여 풍성한 아날로그 음색을 구현합니다. - 포르타멘토 글라이드 (Portamento Glide): Hz 레벨에서
setTargetAtTime보간법을 사용하여 음과 음 사이를 매끄럽게 미끄러지는 현악기 특유의 슬라이드를 구현했습니다. - 마스터 브릭월 리미터 (Master Brickwall Limiter): 모바일/노트북 스피커 등 고출력 시 발생하는 디지털 찢어짐(Clipping)을 완벽 방어하기 위해 출력 최종 단에 압축 필터 노드를 탑재했습니다. (
Threshold: -3.5dB,Ratio: 20:1,Attack: 2ms,Release: 80ms) - 2.5D 홀로그램 및 오실로스코프 시각화: 일렁이는 액상 유리관 파형(Liquid Wave Oscilloscope)을 이중 HTML5 Canvas로 부드럽게 연출합니다.
핵심 코드 (Web Audio DSP Routing & Master Limiter Chain)
// useThereminAudio.ts - 오디오 노드 라우팅 및 리미터 설계 const startAudio = useCallback(() => { if (engineRef.current) return; const ctx = new (window.AudioContext || (window as any).webkitAudioContext)(); // 1. 소스 노드 생성 (듀얼 오실레이터) const oscSine = ctx.createOscillator(); const oscTri = ctx.createOscillator(); const sineGain = ctx.createGain(); const triGain = ctx.createGain(); const voiceGain = ctx.createGain(); // 2. 필터 및 이펙터 노드 생성 const filter = ctx.createBiquadFilter(); const dryGain = ctx.createGain(); const convolver = ctx.createConvolver(); const reverbGain = ctx.createGain(); const delay = ctx.createDelay(1.0); const delayFeedback = ctx.createGain(); const delayGain = ctx.createGain(); const analyser = ctx.createAnalyser(); // 3. 마스터 브릭월 리미터(DynamicsCompressorNode) 체인 설정 (찢어짐 방지) const limiter = ctx.createDynamicsCompressor(); limiter.threshold.setValueAtTime(-3.5, ctx.currentTime); // -3.5dB 이상일 때만 자동 압축 limiter.knee.setValueAtTime(8, ctx.currentTime); limiter.ratio.setValueAtTime(20, ctx.currentTime); // 20:1 리미팅 limiter.attack.setValueAtTime(0.002, ctx.currentTime); // 2ms 초고속 리미팅 limiter.release.setValueAtTime(0.08, ctx.currentTime); // 4. 노드 병렬/직렬 결합 및 이펙터 믹싱 oscSine.connect(sineGain); oscTri.connect(triGain); sineGain.connect(voiceGain); triGain.connect(voiceGain); voiceGain.connect(filter); // Dry 신호 연결 filter.connect(dryGain); dryGain.connect(analyser); // Reverb 이펙터 연결 convolver.buffer = createImpulseResponse(ctx); // 무네트워크 리버브 버퍼 임펄스 데이터 filter.connect(reverbGain); reverbGain.connect(convolver); convolver.connect(analyser); // Delay 이펙터 연결 및 피드백 루프 filter.connect(delayGain); delayGain.connect(delay); delay.connect(delayFeedback); delayFeedback.connect(delay); delay.connect(analyser); // 최종 리미터 및 스피커 연결 analyser.connect(limiter); limiter.connect(ctx.destination); oscSine.start(); oscTri.start(); }, []);
5. 미래 확장성 및 고도화 계획
- 웹캠 입력 미러링 및 사용자 손 커스텀 네온 스킨/파티클 브러시 테마 다양화
- 녹음 기능 및 연주 음원 파일 Local WAV 다운로드 모듈 지원