fix: normalize ambience loudness for v0.2.5

This commit is contained in:
oz
2026-10-14 12:12:13 +00:00
parent 812540c743
commit 91aff66445
390 changed files with 97709 additions and 257 deletions
+43 -13
View File
@@ -1,7 +1,9 @@
# 단어를 맞춰라 · Find-Word v0.2.3
# 단어를 맞춰라 · Find-Word v0.2.5
소음 속에 숨은 한국어 단어를 듣고 찾는 반응형 웹 게임입니다.
**v0.2.5 exact 자산 릴리스 승인:** Oz의 현재 8 WAV 청취 인수로 릴리스 gate를 통과합니다. ASR 실패는 그대로이며 법적/privacy clearance는 없습니다. 배포하지 않았습니다.
**Designed by OZ at Heat-T Medical Inc.**
Canonical repository: [OZ-Group/Find-Word](https://source.ibit.kr/OZ-Group/Find-Word).
@@ -38,7 +40,8 @@ npm run dev
- 에스의 안내가 배경에 묻힌 뒤 목표 문장이 나옵니다. 재생 후 질문에 답합니다.
- 시작 난이도 1~5를 고르고 정확히 **3문항**을 같은 단계에서 풉니다. 단계 기본값은 **SNR +6, +3, 0, −3, −6 dB**입니다.
- 목표 음성 SNR을 **−12~+12 dB, 1 dB 간격**으로 직접 조절할 수 있습니다. 재생 중 변경은 다음 재생·재청취와 남은 문제부터 적용합니다.
양수는 음성이 배경보다 크고, 0은 같고, 음수는 더 작다는 뜻입니다.
배경 크기는 고정되고 양수는 음성을 기준보다 크게, 0은 기준 크기로, 음수는 작게 재생합니다.
표시 dB는 음성 기준 gain의 변화이며 환경별 실측 RMS 비율이나 물리적 음압이 아닙니다.
- 다시 듣기는 감점하지 않습니다. 정답은 `단계 × 100점`, 연속 정답 보너스는 문항별 최대 20점, 라운드 합계 최대 30점입니다 (0 + 10 + 20점, 1단계 만점 330점).
- 정상 결과에서 다음 단계의 새 3문항을 바로 시작합니다. 5단계에서는 같은 단계 재도전과 홈 복귀를 제공합니다. 수동 SNR은 다음 라운드에도 유지되고, 홈 복귀 시 선택한 시작 단계의 기본값으로 돌아갑니다.
- 언제든 **문제 풀이 종료**를 누르면 즉시 오디오를 취소하고 **응답 수·정답 수**를 보여 줍니다. 무응답은 오답으로 세지 않고 정답률은 `— / 응답 없음`, 답하지 않은 단계는 `미진행`으로 표시합니다. 결과에서 **처음 화면으로** 돌아갑니다.
@@ -86,8 +89,9 @@ Chromium sandbox는 기본으로 켭니다. sandbox를 지원하지 않는 격
브라우저 테스트는 기존 `dist/`를 사용하므로 소스 변경 후 먼저 빌드하세요.
실제 음성 재생이 끝나기를 기다려 몇 분이 걸립니다. 로컬 4173 포트를
테스트 중에만 열고 종료합니다. 스크린샷과 109개 WAV의 query URL·해시·디코드
결과는 `test-results/`에 저장합니다. 현재 리뷰 인수 기록은
`.agent/evidence-v0.2.3/review-fixes/`에 보존합니다. 기존 v0.1/v0.1.1 및 v0.2.3 증거는 덮어쓰지 않습니다.
결과는 `test-results/`에 저장합니다. 현재 구현·검증 기록은
`.agent/evidence-v0.2.5/review-fixes/`와 [.agent/RESULT-v0.2.5.md](.agent/RESULT-v0.2.5.md)에 보존합니다.
이전 리뷰 인수 기록은 `.agent/evidence-v0.2.3/review-fixes/`에 있습니다. 기존 v0.1/v0.1.1 및 v0.2.3 증거는 덮어쓰지 않습니다.
## 음성과 문서
@@ -96,9 +100,9 @@ Chromium sandbox는 기본으로 켭니다. sandbox를 지원하지 않는 격
rate `-6%`, pitch `-4Hz`이며 FFmpeg로 **24kHz mono PCM16**으로 변환합니다.
생성 시 네트워크가 필요하며 앱은 저장된 WAV만 재생합니다. 환경음은 공개 라이선스의 실제 현장 녹음 8개를 각 12초로 변환해 번들합니다. 생성 음성의 독점 권리를 주장하지 않습니다.
intro와 목표 WAV는 모두 `/audio/파일명.wav?v=0.2.3`로 요청합니다.
intro와 목표 WAV는 모두 `/audio/파일명.wav?v=0.2.5`로 요청합니다.
`src/audio/assets.ts`의 자산 버전 한 곳을 사용하며, 같은 파일명으로 음성을
교체할 때 이 값을 갱신해 기존 7일 캐시와 구분합니다. 배경은 `/ambience/환경.wav?v=0.2.3`입니다. 제품 버전은 0.2.3입니다.
교체할 때 이 값을 갱신해 기존 7일 캐시와 구분합니다. 배경은 `/ambience/환경.wav?v=0.2.5`입니다. 제품 버전은 0.2.5입니다.
Linux에서 Python 3.11 이상과 FFmpeg를 준비한 뒤 다음 명령을 사용합니다.
클라이언트 버전을 고정해도 원격 모델 변경으로 동일 바이트 재생성은 보장하지 않습니다.
@@ -114,12 +118,37 @@ npm run audio:generate
요청별 60초 제한과 최대 3회 시도를 적용하며, 실패 시 기존 자산을 보존합니다.
청취 샘플: [안내](public/audio/intro.wav), [행운의 사과](public/audio/luck-apple.wav).
현장음의 현재 privacy screening 구간은 mall 36–48초, market 24–36초, cafe 0–12초입니다.
정확한 최종 WAV의 tiny-model VAD 검사에서 세 구간 모두 segment 0개로 `requiredEmptyPassed=true`입니다.
이전 실패와 no-VAD 환각 가능 text 증거는 보존했으며 no-VAD 결과는 지정 VAD gate를 대체하지 않습니다.
빈 결과도 말소리·음악의 부재를 증명하지 않습니다. 독립적인 사람 청취 인증과 법적/privacy clearance는 수행하지 않았지만,
제품 소유자 Oz가 2026-10-14 제공된 8개 최종 WAV 검수 묶음을 기준으로 **현재 자산 그대로 릴리스를 진행하도록 승인**했습니다.
설정·해시·한계와 보존 경로는 [오디오 provenance](docs/AUDIO_PROVENANCE.md#최종-privacy-excerpt-refinement)를 참조하세요.
현장음은 원본·저작자·라이선스·12초 선택 구간을 유지하고 **−32.5 LUFS**로 맞췄습니다.
전용 FFmpeg 6.1.1 `ebur128=peak=true`가 최종 WAV의 릴리스 계기입니다. 8개 모두 **−32.5 LUFS,
spread 0.0 LU**, 최대 true peak **−6.2 dBTP**입니다. 수용 조건은 목표 ±0.2 LU,
spread ≤0.4 LU, true peak ≤−6 dBTP이며 생성기의 내부 ceiling은 −6.2 dBTP입니다.
정확한 faded PCM을 측정해 `volume=<gain_db>dB:precision=double`만 적용하고 PCM16 뒤 새 프로세스로 재측정합니다.
독립 pyloudnorm **0.2.0**/soundfile **0.13.1**도 −32.6062~−32.5291 LUFS, spread **0.0772 LU**로 통과했습니다.
일반 `npm test`는 표준 Python과 FFmpeg로 검사하며 네트워크나 전역 pyloudnorm 패키지를 요구하지 않습니다.
고정 버전·wheel 해시·독립 스크립트는 [review-fixes 증거](.agent/evidence-v0.2.5/review-fixes/README.md)에 있습니다.
이전 loudnorm의 0.01 LU 주장은 전용 ebur128 2.0 LU / pyloudnorm 1.925 LU 결과로 **거부한 역사 기록**입니다.
배경은 브라우저에서 RMS 재정규화하지 않습니다. 모든 환경/SNR의 고정 배경 gain은 **0.4198884518664126**이며
SNR은 목표 음성 상대 gain만 바꿉니다. voice/intro RMS 0.03과 master 동작은 유지합니다.
수학적 상한과 선형 재현 절차는 [설계](docs/ARCHITECTURE.md#오디오)와
[provenance](docs/AUDIO_PROVENANCE.md#v025-loudness-정규화)에 있습니다.
mall 36–48초, market 24–36초, cafe 0–12초를 포함한 8개 구간과 기존 실패/no-VAD 증거를 보존합니다.
새 exact WAV의 동일 faster-whisper 1.2.1 tiny/VAD 검사에서 **market 1 segment, mall/cafe 0개,
requiredEmptyPassed=false**이며 자동 empty-ASR 조건은 여전히 실패입니다.
[실패 원문](.agent/evidence-v0.2.5/review-fixes/final-asr.json)을 보존했습니다. ASR 텍스트는 검증된 전사가 아닙니다.
제품 소유자 Oz는 현재 8 WAV·manifest·notice 검수 ZIP을 받은 뒤 **“승인합니다. 이대로 진행하세요”**라고
2026-10-14T11:29:51Z / 2026-10-14 20:29:51 KST에 회신했습니다(사용자가 전달한 회신).
[기계 판독 승인 기록](.agent/RELEASE-APPROVAL-v0.2.5.json)은 이 정확한 문구·소유자·시각·범위와
ZIP SHA-256 `bb2e974b652df43db4a1f2a59716836e2c521839c724b34d4b71c1b40c3322e5`,
manifest SHA-256 `6433bf23af35f24031c6bbe784dd0abf9330f276da6b8705e47c7a1144a285b7`,
8개 WAV 및 notice 해시를 연결합니다. `productOwnerReleaseApproval=true`, `humanListeningAcceptance=true`,
**`legalPrivacyClearance=false`**이며 과거 v0.2.3 승인을 재사용한 것이 아닙니다.
`python3 scripts/release_approval.py`와 `npm test`의 릴리스 계약은 **동일 설정의 자동 empty-ASR 조건 OR
유효한 exact-byte 소유자 청취 승인**을 검사합니다. 현재 통과 경로는 후자뿐입니다. 승인 기록 누락,
stale WAV/manifest, 다른 ZIP, 문구/범위/시각 누락·변경, 법적 clearance 과장은 실패합니다.
원래 실패 테스트와 로그는 [승인 검증 증거](.agent/evidence-v0.2.5/release-approval/README.md)에 보존합니다.
생성 방법, 도구 라이선스, 합성 음질의 한계는 [AUDIO_PROVENANCE.md](docs/AUDIO_PROVENANCE.md)를
참고하세요. 실제 음량은 출력 장치에 따라 달라지며 표기 dB는 디지털 상대값입니다.
@@ -134,7 +163,8 @@ PD·CC0·CC BY 4.0·CC BY-SA 4.0의 정확한 출처·저작자·변환·해시
시장 파생본은 CC BY-SA 4.0을 유지합니다. 외부 링크는 출처 확인용이며 앱은 이를 요청하지 않습니다.
- [변경 이력](CHANGELOG.md)
- [v0.2.3 구현·검증 결과](.agent/RESULT-v0.2.3.md)
- [v0.2.5 구현·검증 결과](.agent/RESULT-v0.2.5.md)
- [v0.2.3 역사 구현·검증 결과](.agent/RESULT-v0.2.3.md)
- [설계와 상태 전이](docs/ARCHITECTURE.md)
- [Neo를 위한 정적 배포 안내](docs/DEPLOYMENT.md)
- [v0.1.1 RED/GREEN 및 실제 검증 결과](.agent/RESULT-v0.1.1.md)