Files
Dansori_EQ/docs/ARCHITECTURE.md
T
2026-07-04 10:34:46 +09:00

8.4 KiB
Raw Blame History

ARCHITECTURE

1. 기술 스택 (확정)

영역 선택 이유
런타임 .NET 8 최신 LTS, 네이티브 Windows
UI WPF + WPF-UI (lepoco) Fluent Design System / Mica·다크모드 / WinUI 감성. 텍스트 UI 아님
차트 LiveCharts2 애니메이션되는 아름다운 EQ 커브. (대안: ScottPlot=정적·경량)
MVVM CommunityToolkit.Mvvm 소스제너레이터 기반, 보일러플레이트 최소
DB SQLite (Microsoft.Data.Sqlite) 로컬 프로파일 인덱스
AI Anthropic REST (HttpClient) 또는 Anthropic.SDK NuGet 구조화 출력(tool use)
패키징 MSIX 또는 velopack/single-file 배포. 라이선스 제외 옵션과 연동

WPF-UI가 Mica 배경 + Fluent 컨트롤 + 다크테마를 제공해 목업(mockups/main_window.html)의 룩앤필을 네이티브로 재현할 수 있다. 그래프는 LiveCharts2의 CartesianChart로 로그 X축(주파수)

  • 선형 Y축(dB), 영역 그라데이션 채우기.

2. 컴포넌트 구성

DansoriEQ.sln
├─ DansoriEQ.App        (WPF, WPF-UI)  ── Views/ViewModels, 그래프, 프롬프트 독
├─ DansoriEQ.Core       (class lib)
│   ├─ Profiles/         ProfileRepository, AutoEqParser, DbUpdater
│   ├─ Eq/               EqState, Filter(model), ApoRenderer, PreampCalculator
│   ├─ Ai/               ClaudeClient, EqPromptBuilder, EqDeltaSchema
│   └─ Apo/              ApoLocator, ApoConfigInstaller(승격 1회), IncludeWriter
└─ DansoriEQ.Setup      (elevated helper, 최초 1회 UAC — 아래 4장)

3. 데이터 흐름

프로파일 선택 → ProfileRepository.Load(id) → EqState(base)
    → ApoRenderer → IncludeWriter.Write(ai_eq.txt) → APO 라이브 리로드 → 그래프 갱신

프롬프트 입력 → EqPromptBuilder(현재 EqState + 헤드폰 메타 + 요청)
    → ClaudeClient(tool use, EqDeltaSchema) → EqDelta(JSON)
    → EqState.Apply(delta) → PreampCalculator → ApoRenderer → IncludeWriter → APO
    → AI 설명 텍스트를 응답 패널에 표시 / 히스토리 스택 push

4. APO 연동 & 저권한 전략 (중요)

문제: APO의 config.txtC:\Program Files\EqualizerAPO\config\ 아래라 쓰기에 승격 필요. 매번 승격은 "저권한" 원칙 위반.

채택 방식 — "1회 승격 설정, 이후 무승격":

  1. 최초 실행 설정 마법사(DansoriEQ.Setup, UAC 1회):
    • APO 설치 경로 탐지: 레지스트리 HKLM\SOFTWARE\EqualizerAPOInstallPath.
    • 사용자 쓰기 가능한 EQ 파일 준비. 권장: config 폴더 내 ai_eq.txt를 만들고 그 파일(또는 폴더)에 현재 사용자 쓰기 ACL 부여(icacls). 그리고 config.txtInclude: ai_eq.txt 한 줄 추가(중복 방지 검사).
    • 완료 플래그 저장(%LOCALAPPDATA%\DansoriEQ\setup.json).
  2. 이후 실행: 앱은 ai_eq.txt만 갱신 → 승격 불필요. APO가 저장 즉시 리로드.

⚠️ M1에서 검증할 스파이크: APO Include:가 절대경로를 허용하는지 확인.

  • 허용 O → ai_eq.txt%APPDATA%\DansoriEQ\에 두고 절대경로 Include(ACL 불필요, 가장 깔끔).
  • 허용 X(상대경로만) → 위 4-1의 config 폴더 내 파일 + ACL 부여 방식으로. 두 경로 모두 "1회 승격, 이후 무승격"을 만족. 스파이크 결과로 하나 확정.

APO 필터 문법(렌더 타깃):

Preamp: -6.0 dB
Filter 1: ON PK  Fc 3000 Hz Gain 3.0 dB Q 1.20
Filter 2: ON LSC Fc 90 Hz   Gain 4.0 dB Q 0.70
Filter 3: ON HSC Fc 10000 Hz Gain -1.5 dB Q 0.70
  • 타입 매핑: PK=peaking, LSC=low-shelf, HSC=high-shelf, (LP/HP 확장 가능).
  • Preamp = -(양의 게인 총합) 또는 최소 -(최대 양의 게인) − 여유 1dB. 클리핑 방지 필수.

5. 프로파일 DB & 라이선스 분리

폴더 레이아웃

data/
├─ profiles/
│   ├─ open/         ← 재배포 허용(퍼미시브) 소스. 배포 빌드에 포함
│   └─ restricted/   ← 재배포 불가 소스. 배포 빌드에서 제외
├─ manifest.json     ← 소스별 {name, license, distributable, url, commit}
└─ dansorieq.db     ← SQLite 인덱스(open+restricted 모두 인덱싱)

원칙

  • 수집(개발 중 1회): AutoEQ repo를 zip/clone로 확보 → 파싱 → 소스 라이선스에 따라 open/ 또는 restricted/로 분류 저장 → SQLite에 upsert.
  • UI: DB를 조회할 때 라이선스 구분 없이 병합해서 보여준다(IEM/헤드폰만 구분).
  • 배포: 패키징 시 --exclude-restricted 옵션 → restricted/ 폴더와 해당 DB 행 제외. (개인 사용 로컬 빌드는 전체 포함.)
  • DB 스키마:
CREATE TABLE headphone(
  id INTEGER PRIMARY KEY,
  name TEXT NOT NULL,
  brand TEXT,
  type TEXT CHECK(type IN ('iem','headphone')) NOT NULL,
  source TEXT,             -- 측정/소스명
  license TEXT,            -- 예: 'CC-BY', 'restricted'
  distributable INTEGER,   -- 0/1  (UI에선 필터하지 않음)
  target TEXT,             -- 예: 'Harman IE 2019'
  preamp_db REAL,
  filters_json TEXT,       -- [{type,fc,gain,q}]
  raw_text TEXT,           -- 원본 ParametricEQ.txt
  updated_at TEXT
);
CREATE INDEX ix_hp_type ON headphone(type);
CREATE INDEX ix_hp_name ON headphone(name);

앱 내 업데이트

  • "DB 업데이트" → 최신 소스(zip) 재확보 → 파싱 → upsert(변경분만) → manifest commit/날짜 갱신.
  • UI 하단에 N profiles · 최신: YYYY-MM-DD 표시.

6. AI 레이어 스키마 (구조화 출력)

EqDelta (Claude가 tool use로 반환):

{
  "preamp_db": -6.0,
  "filters": [
    { "type": "PK",  "fc": 3000, "gain": 3.0, "q": 1.2, "enabled": true },
    { "type": "LSC", "fc": 90,   "gain": 4.0, "q": 0.7, "enabled": true }
  ],
  "explanation": "보컬 존재감을 위해 3kHz +3dB…",
  "replace": false            // false=현재 상태에 병합, true=전체 교체
}

시스템 프롬프트 요지:

  • 역할: 파라메트릭 EQ 전문가. APO 제약(타입 PK/LSC/HSC, Fc 2020000Hz, Gain ±12dB 권장, Q 0.36) 안에서만 출력.
  • 입력으로 현재 EqState + 헤드폰 모델/타입 + 사용자 요청 제공 → 요청을 delta로 반영.
  • 오디오 상식 힌트(보컬≈2–5kHz, 저음 단단히≈4080Hz 무게+150250Hz 뭉침 컷, 치찰음≈68kHz).
  • Preamp 안전값 계산 규칙 명시.
  • 런타임 모델: 기본 Claude Sonnet(요청당 25k 토큰), 옵션으로 Opus.

7. 오픈 이슈 → DEV_PLAN 참조

  • APO Include 절대경로 허용 여부(스파이크).
  • AutoEQ repo 구조/소스 라이선스 최신 상태 확인(수집 스크립트에서).
  • 다중 출력 장치별 APO config 타깃팅(고급 옵션, MVP 이후).

8. EQ 프리셋 공유 포맷 (.tweq)

사용자가 만든 EQ를 다른 사용자와 공유하기 위한 파일. JSON, 확장자 .tweq.

{
  "format": "dansorieq.eq",
  "version": 1,
  "app_version": "0.1.0",
  "created_utc": "2026-07-01T12:00:00Z",
  "author_note": "밝고 보컬 중심 튜닝",
  "target": {
    "name": "Truthear x Crinacle Zero",
    "brand": "Truthear",
    "type": "iem",
    "source": "AutoEQ",
    "target_curve": "Harman IE 2019"
  },
  "eq": {
    "preamp_db": -6.0,
    "filters": [
      { "type": "PK", "fc": 3000, "gain": 3.0, "q": 1.2, "enabled": true }
    ]
  },
  "history": [
    { "role": "user", "text": "보컬 가까이, 저음 단단히", "ts": "..." },
    { "role": "ai",   "text": "3kHz +3dB, 180Hz -2.5dB…",  "ts": "..." }
  ]
}
  • 내보내기: 현재 EqState + 대상 기기 메타 + 대화 히스토리(간략)를 직렬화해 저장.
  • 가져오기: 검증(format/version, 값 범위 클램프, 크기 상한) → 정보 패널(대상 기기 / 히스토리 / 작성자 노트) 표시 → EQ 적용.
  • 라이선스 안전: 파일엔 측정 데이터가 아니라 기기 이름/메타만 포함 → 재배포 문제 없음.
  • 보안: history 텍스트는 표시 전용(실행/링크 처리 안 함), 항목 수·길이 상한, API 키 미포함.

9. 설정 & Claude API 키 관리

  • 별도 설정 화면(WPF-UI NavigationView: Home/EQ ↔ Settings).
  • 섹션: [AI · API 키] / [테마] / [APO] / [데이터베이스].
  • API 키: 등록 / 삭제 / 교체, "연결 테스트", DPAPI 암호화 저장(%LOCALAPPDATA%\DansoriEQ).
  • 모델 선택: 기본 Claude Sonnet / 옵션 Opus.
  • 키 미등록 시 프롬프트 독 비활성 + 등록 안내.