물리 마이크 입력을 온디바이스 AI(DeepFilterNet3) 로 실시간 노이즈 억제한 뒤, Zoom·Meet·Slack·Discord·Teams 등에서 선택할 수 있는 가상 마이크("Noise Cancelled Microphone") 로 출력. 로컬 파일 음성 개선도 지원.
# ============================================================
# Crisp 빌드 & 설치 (macOS 13+, Apple Silicon)
# 요구: Xcode 15+ / Swift 5.9+, Rust(cargo: https://rustup.rs), ffmpeg(검증용)
# ============================================================
git clone https://github.com/rtzr/crisp.git && cd crisp
chmod +x build.sh build-app.sh scripts/*.sh poc/model/run_poc.sh
# 1) 의존성 준비 (최초 1회): DeepFilterNet 클론 + libdf.dylib/모델 vendoring.
# tract를 컴파일하므로 수 분 소요. 이 단계가 없으면 앱 빌드가 실패한다.
./scripts/fetch-deps.sh
# 2) 빌드
./build.sh # → build/CrispAudio.driver (HAL 가상 마이크, universal, ad-hoc 서명)
./build-app.sh # → build/Crisp.app (메뉴바 앱 + 모델 번들)
# 3) 설치: 앱→/Applications, 드라이버→/Library, coreaudiod 재시작 (GUI 관리자 인증 필요)
./scripts/package.sh
open build/Crisp-0.1.0.pkg
# 4) 검증: 가상 마이크 노출 + 녹음
./scripts/verify-driver.sh
# 사용: 회의/녹음 앱의 마이크에서 "Noise Cancelled Microphone" 선택
# 메뉴바 Crisp 아이콘에서 ON/강도/바이패스/저지연 조절
#
# (개발 중 드라이버만 빠르게) sudo ./scripts/install-driver.sh
# (제거) sudo ./scripts/uninstall-driver.sh모든 처리는 로컬(서버 업로드 없음, 순수 Rust
tract추론 — 외부 런타임 불필요). 검증: 가상 마이크 설치/녹음, end-to-end 실시간 loopback, 30분 무중단(crash 0·dropout 0), 모델 RTF ≈ 0.10, DNSMOS OVRL +0.55 / BAK +1.45 —docs/test-report.md. 구현 현황:docs/STATUS.md.
| 도구 | 용도 | 비고 |
|---|---|---|
| macOS 13+ (Apple Silicon) | 타깃 OS | universal 빌드 |
| Xcode 15+ / Swift 5.9+ | 앱·드라이버 빌드 | |
| Rust (cargo) | DeepFilterNet libdf 빌드 |
https://rustup.rs |
| ffmpeg | 테스트 픽스처 생성·검증용만 | 제품 미포함 |
실시간: 메뉴바 Crisp → 노이즈 캔슬링 ON + 입력 마이크 선택 → 회의 앱 마이크에서 "Noise Cancelled Microphone" 선택. 강도(약/보통/강)·바이패스·저지연 모드 조절 가능.
파일: 설정 창 → 파일 탭 → 오디오/비디오(wav/mp3/m4a/mp4) 드래그앤드롭 → 출력 포맷(wav/m4a) 선택 → 강도 슬라이더(0–100 dB) 로 단일 처리, 또는 배치 모드로 여러 강도(예 12/24/48/100 dB)를 한 번에 출력해 비교·저장.
./poc/model/run_poc.sh # 모델 RTF·노이즈 감소
./scripts/e2e-test.sh # end-to-end: model→가상마이크→녹음 (드라이버 설치 필요)
./scripts/stability-test.sh 1800 # 30분 안정성 (crash/dropout)
BIN="$(cd app && swift build --show-bin-path)"
"$BIN/dftool" engine/models/DeepFilterNet3_onnx.tar.gz 100 build/in.f32 out.f32 chunked # 스트리밍 정확성
"$BIN/filetool" input.mp3 out.m4a m4a # 파일 처리driver/CrispAudioDriver/ HAL Audio Server Plug-in (C) — 가상 마이크 (loopback)
app/Package.swift SwiftPM: CDeepFilter / CrispEngine / CrispApp / dftool·filetool·mictool
Sources/CDeepFilter/ libdf C 헤더(df.h) + modulemap
Sources/CrispEngine/ 순수 DSP/모델(AVFoundation): DeepFilterSuppressor, FileEnhancer,
VirtualMicOutput(AUHAL), CoreAudioDevices ← 앱·CLI 공유
Sources/CrispApp/ SwiftUI 메뉴바 앱 (AppState, AudioEngineController, Views)
Sources/{dftool,filetool,mictool}/ 검증 CLI
engine/CDeepFilter/lib/ libdf.dylib (fetch-deps 생성, gitignore)
engine/models/ DeepFilterNet3 모델 (fetch-deps 생성, gitignore)
scripts/ fetch-deps / install / verify / package / e2e / stability
docs/ architecture · STATUS · test-report · install · acceptance-checklist · known-issues
poc/model/ DeepFilterNet 클론(gitignore) + run_poc.sh
아키텍처: docs/architecture.md · 사람/계정 필요 인수 항목: docs/acceptance-checklist.md
| Phase | 내용 | 상태 |
|---|---|---|
| 1a 가상 마이크 | HAL Audio Server Plug-in | ✅ 설치·노출·녹음 |
| 1b 모델 | DeepFilterNet3 추론 | ✅ RTF 0.10, 노이즈 ~30dB↓ |
| 2 실시간 엔진 | capture→model→가상마이크 | ✅ end-to-end loopback |
| 3 앱 | 메뉴바/온보딩/설정 | ✅ |
| 4 파일 처리 | ffmpeg-free (AVFoundation) | ✅ mp3→m4a, mp4→wav |
| 5 패키징 | 서명/notarization/pkg | 🔶 pkg ✅, notarize는 Apple 계정 |
AI 코딩 에이전트가 안전하게 작업하기 위한 지침. 빌드/설치는 맨 위 코드블록 참조.
Repo map (수정 위치):
- 가상 마이크 동작 →
driver/CrispAudioDriver/CrispAudioDriver.c(Crisp_DoIOOperation의 loopback ring) - 모델 추론(실시간·파일 공통) →
app/Sources/CrispEngine/DeepFilterSuppressor.swift(libdf C-API) - 파일 처리 →
app/Sources/CrispEngine/FileEnhancer.swift(AVAssetReader→libdf→AVAudioFile) - 가상 마이크 출력 →
app/Sources/CrispEngine/VirtualMicOutput.swift(AUHAL) - 실시간 캡처/라우팅 →
app/Sources/CrispApp/Audio/AudioEngineController.swift - UI/상태 →
app/Sources/CrispApp/{Views,Model}
Invariants — 깨면 안 됨:
- 장치 UID
"CrispAudioDevice:0"는 드라이버(kDevice_UID)와 Swift(CoreAudioDevices.crispVirtualUID)에서 동일. - 모델은 48 kHz mono, hop 480(=10ms). 다른 레이트는
AVAudioConverter로 48k 변환 후 처리. DeepFilterSuppressor는 stateful 스트리밍 — hop을 연속·순서대로 공급(carry 버퍼 보장). 검증:dftool ... chunked출력이 aligned와 bit-identical.- 실시간/파일 경로에 ffmpeg·외부 프로세스 의존 금지 (파일도 AVFoundation).
- UI 메터 갱신은 ~15Hz throttle +
MeterState격리 (오디오 탭 ~100Hz → 메인스레드 폭주 방지). 되돌리지 말 것. - HAL 드라이버는 Apple Silicon에서 서명 필수(ad-hoc 가능), 팩토리 심볼
CrispAudioDriver_Createexport 유지(CRISP_EXPORT). libdf.dylib는@rpath/libdf.dylibinstall name + 앱Resources/librpath로 로드.
에이전트가 할 수 없는 것 (사람/계정): 드라이버 설치(관리자 인증), Developer ID notarization(Apple 계정), GUI 회의앱 실통화·A/B blind 청취 → docs/acceptance-checklist.md.
DeepFilterNet(libDF + 모델 weight), tract: MIT / Apache-2.0 (상용 가능). Crisp 드라이버/앱/엔진: 자체 작성. 상세: LICENSES.md