Skip to content

Repository files navigation

🎧 EarCut Studio

React Vite JavaScript Web Audio API ONNX Runtime Web Vercel

브라우저에서 재생 중인 컴퓨터 소리(유튜브, 웹 플레이어 등)를 실시간으로 캡처하고, 원하는 구간을 잘라 고음질 WAV 파일로 저장하는 웹 오디오 샘플링 도구입니다. 별도의 프로그램 설치 없이 Web Audio API화면 공유(탭 오디오 캡처) API만으로 동작하며, 추출한 샘플은 브라우저에서 직접 구동되는 로컬 AI 모델(Demucs) 로 보컬/드럼/베이스/반주 트랙으로 분리할 수 있습니다.

🔗 Live Demo: ear-cut.vercel.app

✨ 주요 기능

  • 탭 오디오 캡처getDisplayMedia로 브라우저 탭의 오디오 스트림을 직접 녹음 (외부 소프트웨어/드라이버 불필요)
  • 실시간 파형 모니터링 — Canvas 기반 오디오 비주얼라이저로 녹음 중 파형을 실시간 확인
  • Always-on-Top 컨트롤러 — Document Picture-in-Picture API로 다른 창 위에 항상 떠 있는 독립 컨트롤러 제공
  • PiP 미지원 브라우저 대응 — PiP를 지원하지 않는 브라우저에서는 페이지 내 드래그 가능한 모달로 자동 대체
  • 고음질 WAV 내보내기 — 녹음된 오디오를 압축 없는 16-bit Stereo PCM WAV로 인코딩
  • AI 보컬/악기 분리Demucs ONNX 모델을 onnxruntime-web(WebGPU/WASM) + Web Worker로 브라우저에서 직접 실행해, 60초 이하 샘플을 Vocal/Drum/Bass/Inst 4트랙으로 분리 (서버 업로드 없이 로컬 연산, 모델은 최초 1회 다운로드 후 Cache API로 캐싱)
  • 샘플 영구 저장 — 녹음/분리 결과를 IndexedDB에 저장해 새로고침 후에도 유지
  • 샘플 목록 관리 — 원본 및 분리된 각 트랙의 재생/다운로드/삭제 지원

🎬 데모

EarCut Studio 사용 흐름 데모

EarCut Studio 랜딩 화면

사용 흐름

STEP 1. 소스 연결 STEP 2. 오디오 공유
컨트롤러 열기소리 소스 연결로 오디오를 재생 중인 탭을 선택 공유 대화상자 하단의 "오디오 공유(Share audio)" 체크박스 활성화
STEP 3. 샘플링 STEP 4. 샘플 목록
샘플링 시작/중지로 원하는 구간을 녹음, WAV로 자동 인코딩 녹음된 샘플을 목록에서 바로 재생·다운로드
STEP 5. AI 분리 실행 STEP 6. 스템 결과
샘플 카드를 펼쳐 "보컬/악기 분리 실행" 클릭 (60초 이하 샘플만 지원) Vocal/Drum/Bass/Inst 4트랙이 개별 재생·다운로드 가능하게 표시

앱 내 헤더의 "컨트롤러 사용법" 패널에서도 동일한 과정을 스크린샷과 함께 단계별로 확인할 수 있습니다.

👤 My Role

개인 사이드 프로젝트로 기획부터 설계, 구현, 배포까지 단독으로 진행했습니다.

  • 탭 오디오 캡처 파이프라인 설계·구현getDisplayMedia + AudioContext 기반으로 외부 드라이버 없이 브라우저 탭 오디오를 직접 캡처하는 useAudioCapture 훅 작성
  • 무손실 WAV 인코더 직접 구현 — 서버나 외부 인코딩 라이브러리 없이 AudioBuffer를 16-bit Stereo PCM WAV로 변환하는 인코더를 클라이언트 단에서 완결 (utils/wav.js)
  • Always-on-Top 컨트롤러 UX 설계 — Document Picture-in-Picture API로 독립 팝업 컨트롤러를 구현하고, PiP 미지원 브라우저를 위한 드래그 가능한 인페이지 모달 폴백을 별도로 설계
  • AI 음원 분리 파이프라인 통합 — ONNX Runtime Web + Web Worker로 Demucs 모델 추론을 메인 스레드와 분리해 UI 끊김 없이 로컬에서 실행되도록 구성 (separation.worker.js)
  • 교차 출처 격리(COOP/COEP) 이슈 해결 — 스레드 WASM 백엔드 초기화 실패 원인을 규명하고 dev(vite.config.js)/배포(vercel.json) 환경에 헤더를 일관되게 설정
  • 제한된 네트워크 환경 대응 — 외부 CDN 의존으로 인한 WASM 로딩 실패 문제를 ONNX Runtime WASM/JSEP 바이너리 로컬 내장(public/)으로 해결
  • AI 모델 로딩 진행률 UX 개선 — 캐시 히트 시 진행률 조기 완료, 모델 컴파일 단계 멈춤 현상 등 여러 체감 버그를 재현하고 순차적으로 수정
  • 영속화 계층 설계 — IndexedDB 기반 샘플/스템 저장소(utils/db.js)를 설계해 새로고침 후에도 결과가 유지되도록 구현

🛠 Tech Stack

Area Stack
Frontend React 19, Vite 8
Audio Capture/Encoding Web Audio API, getDisplayMedia(MediaRecorder 계열), 자체 구현 WAV 인코더
AI Inference ONNX Runtime Web (WebGPU 우선 / WASM 폴백), demucs-web, Web Worker
Storage IndexedDB, Cache API (AI 모델 캐싱)
UI/UX Document Picture-in-Picture API, lucide-react
Deploy Vercel
Tooling ESLint (flat config)

🏗 Architecture

별도 백엔드 서버 없이 브라우저 안에서 캡처 → 인코딩 → 저장 → AI 추론까지 모두 처리하는 클라이언트 단일 구조입니다.

1. "컨트롤러 열기" 클릭
   → PiP 지원 브라우저: Always-on-Top 팝업 창 (documentPictureInPicture)
   → 미지원 브라우저: 페이지 내 드래그 가능한 모달로 폴백 (useDraggable)

2. "소리 소스 연결" 클릭
   → getDisplayMedia로 탭 오디오 스트림 획득 (useAudioCapture)
   → AudioContext에 연결, Canvas로 실시간 파형 시각화

3. "샘플링 시작/중지"
   → 캡처된 PCM을 useWavRecorder에서 16-bit Stereo WAV로 인코딩 (utils/wav.js)
   → 결과를 IndexedDB(EarCutStudioDB)에 영속화 → 새로고침 후에도 샘플 유지

4. "보컬/악기 분리 실행" (선택, 60초 이하 샘플)
   → 샘플 PCM을 Web Worker(separation.worker.js)로 전달 (메인 스레드 논블로킹)
   → onnxruntime-web이 ONNX 모델을 Cache API로 캐싱하며 로드 (WebGPU 우선, WASM 폴백)
   → demucs-web이 Vocal / Drums / Bass / Inst 4트랙으로 분리
   → 분리된 각 트랙을 WAV로 인코딩해 IndexedDB에 저장, UI에서 개별 재생/다운로드

프로젝트 구조

src/
├── App.jsx                        # 랜딩 화면 및 컨트롤러 오픈/PiP 상태 관리
├── components/
│   ├── AudioSampler.jsx           # 오디오 캡처, 녹음, WAV 인코딩, 시각화, 샘플/스템 목록 UI
│   └── ControllerGuide.jsx        # 컨트롤러 열기~AI 분리 결과 확인까지 단계별 사용법 가이드 패널
├── hooks/
│   ├── useAudioCapture.js         # getDisplayMedia 탭 오디오 캡처, AudioContext 관리
│   ├── useWavRecorder.js          # 녹음, WAV 인코딩, IndexedDB 영속화(recordings/stems)
│   ├── useAudioSeparation.js      # Web Worker 기반 AI 분리 오케스트레이션 및 진행률 추정
│   └── useDraggable.js            # PiP 미지원 시 페이지 내 모달 드래그 처리
├── workers/
│   └── separation.worker.js       # onnxruntime-web + demucs-web 실행, 모델 다운로드/캐싱(Cache API)
├── utils/
│   ├── db.js                      # IndexedDB(EarCutStudioDB) 래퍼
│   └── wav.js                     # AudioBuffer → WAV 인코딩
├── assets/guide/                  # 사용법 가이드 스텝별 스크린샷
├── App.css / index.css            # 전역 스타일, 디자인 토큰(CSS 변수)
└── main.jsx                       # 엔트리 포인트

public/
└── ort-wasm-simd-threaded.*       # onnxruntime-web WASM/WebGPU(jsep) 런타임 바이너리 (정적 서빙, CDN 미사용)

🧩 Key Challenges / Troubleshooting

  • 스레드 WASM 실행을 위한 교차 출처 격리 문제 — onnxruntime-web의 WebGPU/threaded WASM 백엔드가 별다른 에러 메시지 없이 초기화에 실패하는 문제를 만나, 원인이 SharedArrayBuffer 사용에 필요한 교차 출처 격리(COOP/COEP) 헤더 누락임을 확인. vite.config.js(dev 서버)와 vercel.json(배포) 양쪽에 동일한 헤더를 설정해 로컬-배포 환경 간 동작 차이를 없앴습니다.
  • 제한된 네트워크 환경에서의 CDN 차단 대응 — onnxruntime-web이 기본적으로 외부 CDN에서 WASM 바이너리를 받아오는 구조라, 특정 네트워크 환경에서 로딩이 막혀 no available backend found 오류가 발생하는 것을 확인. WASM/JSEP 런타임 파일 전체를 public/에 직접 내장하고 ort.env.wasm.wasmPathsimport.meta.env.BASE_URL로 지정해 정적 서빙으로 전환, 배포 경로(서브 디렉토리 포함)에도 대응하도록 만들었습니다.
  • AI 모델 로딩 진행률 UX 버그 다수 수정 — ① 모델이 이미 캐싱된 경우 진행률이 조기에 100%로 표시되는 문제, ② 다운로드 완료 후 실제로는 ONNX 모델 컴파일이 진행 중인데도 UI가 멈춘 것처럼 보이는 문제를 각각 재현·수정. Cache API 응답을 스트리밍으로 읽어 실제 바이트 기준 진행률을 계산하고, "다운로드 → 컴파일 → 처리" 단계를 UI 상태로 명시적으로 분리해 사용자가 진행 상황을 오해하지 않도록 개선했습니다.

🚀 시작하기

요구 사항

  • Node.js 18 이상
  • Chrome/Edge 등 Chromium 기반 브라우저 권장 (탭 오디오 캡처 및 Document PiP는 Chromium 계열에서만 완전히 지원됩니다)
  • AI 분리 기능은 스레드 WASM 실행을 위해 Cross-Origin-Opener-Policy: same-origin / Cross-Origin-Embedder-Policy: require-corp 헤더(교차 출처 격리)가 필요합니다. vite.config.js(dev)와 vercel.json(배포)에 이미 설정되어 있습니다.

설치 및 실행

npm install
npm run dev       # 개발 서버 실행 (HMR)

빌드 / 미리보기

npm run build      # 프로덕션 빌드 (dist/)
npm run preview    # 빌드 결과 미리보기

린트

npm run lint

⚠️ 브라우저 지원 참고

  • 탭 오디오 캡처(getDisplayMedia audio)와 Document Picture-in-Picture는 Chrome/Edge 등 Chromium 계열에서만 안정적으로 동작합니다.
  • Firefox/Safari 등에서는 오디오 공유 옵션이 없거나 PiP가 지원되지 않아 기능이 제한될 수 있습니다.
  • AI 보컬/악기 분리는 WebGPU를 우선 시도하고 WASM으로 폴백합니다. 브라우저 메모리 한계로 60초를 초과하는 샘플과 모바일 기기에서는 비활성화됩니다.
  • public/ort-wasm-simd-threaded.* 런타임 파일들은 반드시 저장소에 커밋되어 배포되어야 합니다. 빠지면 AI 분리 시 no available backend found 오류가 발생합니다.

🔧 Development Process

  • 커밋 컨벤션: feat, fix, docs, refactor, style, design 등 Conventional Commits 스타일 태그로 변경 단위를 구분해 커밋했습니다.
  • 코드 품질: ESLint(flat config)로 코드 스타일을 일관되게 유지했습니다.
  • 개발 방식: 1인 개발로 별도 브랜치 전략 없이 main 브랜치에 직접 커밋하는 방식으로 진행했습니다.

📮 Contact

About

브라우저 탭 오디오를 실시간 캡처해 WAV로 저장하고, 로컬 AI(Demucs)로 보컬/악기를 분리하는 웹 오디오 샘플링 도구

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages