# Pattern Chain Display – Implementation Plan 작성일: 2026-01-05 대상: APS Pattern Chain 화면 (Chain Viewer/Editor) 목표: “항목 수” 중심의 기존 표시를 유지하면서, **연주 길이/섹션 길이/바 위치**를 친절하게 표시 --- ## 1. 목표(What) ### 1.1 타이틀 바(1줄) 확정 포맷 타이틀 바는 **한 줄에 모두 포함**하며, APS 버전 표기는 제거한다. ```text ▶ Pattern Chain — Items=9, Unique=7, Bars=17, CI=1b ``` 정의: - `Items` = 체인 엔트리(항목) 수 = 화면에 표시되는 줄 수 - `Unique` = 중복 제거한 패턴 파일 수 (파일명 기준) - `Bars` = 재생 기준 총 마디 수 (repeat, half 반영 / Count-in 미포함) - `CI` = Count-in (예: `-`, `1b`, `2b`) --- ## 2. 인덱스/라인 표시 포맷(Option 1 확정) ### 2.1 기본 라인 포맷 - 왼쪽 인덱스는 **엔트리 번호(Items 기준)** 유지 (편집 UX 보호) - 괄호에 **해당 엔트리의 시작 bar** 표시 - 섹션명은 기존처럼 `[...]`로 표시 - 단, **섹션의 “첫 엔트리”에만** 섹션 bar 길이를 `{Nb}` 형태로 추가 ```text NN (bBB): [Section{Nb}] PATTERN xN NN (bBB): [Section] PATTERN xN NN (bBB): PATTERN xN # 섹션이 없으면 생략 ``` 예시: ```text 01 (b01): [Verse{8b}] AFC_P002.ADT x1 02 (b03): [Verse] AFC_P003.ADT x1 03 (b05): [Verse] AFC_P004.ADT x1 04 (b07): [Verse] AFC_P003.ADT x1 05 (b09): AFC_B030.ADT x1 06 (b09): [Chorus{9b}] AFC_P005.ADT x1 07 (b11): [Chorus] AFC_P006.ADT x1 08 (b13): [Chorus] AFC_P007.ADT x1 09 (b15): [Chorus] AFC_h001.ADT x1 ``` --- ## 3. 계산 규칙(How) ### 3.1 play bars 계산 (핵심) 엔트리마다 “재생 bar 수”를 계산한다. - normal pattern: `2 bars` - half pattern (`_h` / `_H`): `1 bar` - repeat: `xN`이면 위 bar 수에 `N`을 곱한다. ```text entry_play_bars = base_bars(pattern) * repeat_count ``` 여기서: - `base_bars(pattern)`: - half: 1 - normal: 2 > Count-in(CI)은 **Bars** 및 start bar 계산에 **절대 포함하지 않는다**. ### 3.2 start bar(bBB) 계산 체인 시작을 `b01`로 두고, 누적 재생 bar 수로 다음 엔트리의 시작 bar를 계산한다. ```text start_bar = 1 + cumulative_bars_before_this_entry ``` 표기: - `b01, b02, ...` 형태 - 최소 2자리 고정(`b01`) 권장 (필요 시 3자리로 확장) ### 3.3 섹션 bar 길이 `{Nb}` 계산 섹션 이름이 같은 엔트리들의 `entry_play_bars`를 합산하여 섹션 길이를 구한다. ```text section_bars[section] = Σ entry_play_bars for entries in that section ``` 표기 규칙: - `{8b}` 처럼 `b`를 포함하여 마디 단위임을 명확히 한다. ### 3.4 섹션 “첫 엔트리” 판정 출력 순회 중, 섹션이 처음 등장할 때만 `{Nb}`를 붙인다. ```text if section and section not in seen_sections: show "[Section{Nb}b]" seen_sections.add(section) else: show "[Section]" ``` 섹션이 비어있거나 None이면: - 섹션 표기를 생략 - `{Nb}`도 없음 --- ## 4. 타이틀의 값 계산(Title Metrics) ### 4.1 Items ```text Items = len(chain_entries) ``` ### 4.2 Unique - 기본 정의: 패턴 파일명 기준(set) - repeat(`xN`)은 “고유 패턴 수”에 영향을 주지 않음 ```text Unique = len(set(entry.filename for entry in chain_entries)) ``` ### 4.3 Bars ```text Bars = Σ entry_play_bars for all entries ``` ### 4.4 CI - 기존 체인 메타/설정에서 가져온다. - 표기: - 없음: `CI=-` - 1 bar: `CI=1b` - 2 bar: `CI=2b` --- ## 5. 구현 단계(Plan) ### Phase A – 계산 함수 추가(안전, 재사용 가능) 1. `is_half_pattern(filename or meta)` 2. `entry_play_bars(entry)` 3. `compute_chain_metrics(entries) -> Items, Unique, Bars` 4. `compute_section_bars(entries) -> dict(section->bars)` 5. `compute_start_bars(entries) -> list(start_bar per entry)` ### Phase B – 출력 포맷 적용(표시만 변경) 1. 타이틀 바 출력 포맷을 확정 문자열로 변경 2. 라인 출력에서 `NN (bBB):`를 추가 3. 섹션 첫 엔트리에서만 `{Nb}`를 삽입 ### Phase C – 검증(회귀 방지) - 기존 체인(32-step normal)에서 표시가 자연스럽고 편집/선택이 동일하게 동작하는지 확인 - half 패턴 포함 케이스에서 Bars/section bars가 기대대로 계산되는지 확인 - repeat(`xN`) 포함 케이스에서 Bars 및 start bar 누적이 맞는지 확인 --- ## 6. 주의점 및 향후 확장 ### 6.1 Half 판정 소스 - 1차: 파일명 `_h###` 규칙 - 2차(가능하면): ADT 메타 `PLAY_BARS=1`을 우선 - 둘이 불일치하면 경고(또는 파일명 우선) 정책 결정 필요 ### 6.2 향후 “부분 비활성(PLAY_STEPS)” 도입 시 - `Bars`는 여전히 bar 단위로 유지하되, - 별도 표기(예: `Trim=3/4`) 같은 방식으로 확장 가능 (본 계획에서는 포함하지 않음) --- ## 7. 완료 기준(Done) - 타이틀이 다음 포맷으로 표시된다: ```text ▶ Pattern Chain — Items=, Unique=, Bars=, CI= ``` - 각 항목이 다음 포맷으로 표시된다: ```text NN (bBB): [Section{Nb}b] filename xN # 섹션 첫 등장 NN (bBB): [Section] filename xN # 섹션 지속 NN (bBB): filename xN # 섹션 없음 ``` - 편집/선택 UX(엔트리 번호 기반)는 기존과 동일하게 유지된다.