Metadata-Version: 2.1
Name: chord-romanizer
Version: 0.1.9
Summary: A library to analyze chord progressions and convert them to Roman numeral analysis.
Home-page: https://github.com/anime-song/chord-romanizer
Author: anime-song
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.7
Description-Content-Type: text/markdown
License-File: LICENSE

# Chord Romanizer

[![PyPI version](https://badge.fury.io/py/chord-romanizer.svg)](https://badge.fury.io/py/chord-romanizer)

Chord Romanizerは、コード進行の解析とディグリーネーム（ローマ数字）表記への変換を行うPythonライブラリです。
複雑なコードや転回形、ハイブリッドコード（分数コード）にも対応しており、文脈（前後のコード）を考慮した解析を行います。

## 特徴
- **文脈考慮**: キーと前後のコードから最適な度数表記を判定します（例: 上行半音進行なら `#IV`、下行なら `bV` を優先するなど）。
- **高度な分数コード解析**:
    - **転回形**: `C/E` -> `I/3` ($I$ の第1転回形)
    - **ハイブリッドコード**: `F/G` (in C) -> `V9sus4` として解釈しつつ `IV/V` と表記可能。
    - **特殊コード対応**: ブラックアダーコード (`Aug/Bass`) やディミニッシュの異名同音判定も自動で行います。
- **転調への対応**: コードごとに個別のキーを指定して解析が可能です。
- **表記の正規化**: `simplify_accidentals` オプションにより、ダブルシャープ/ダブルフラットを読みやすい異名同音に変換可能。

## インストール

PyPIからインストールできます。

```bash
pip install chord-romanizer
```

## クイックスタート

```python
from chord_romanizer import Romanizer, ChordParser

# 1. インスタンス生成 (デフォルトキーを指定可能)
romanizer = Romanizer(default_tonic="C")

# 2. コード進行の準備 (文字列からParsedChordへ変換)
progression_str = ["Dm7", "G7", "Cmaj7", "A7(b9)", "Dm7"]
chords = [ChordParser.parse(c) for c in progression_str if c]

# 3. 解析 (annotate_progression)
# 結果は RomanizedChord オブジェクトのリスト
results = romanizer.annotate_progression(chords)

# 4. 結果の表示
for res in results:
    input_symbol = res.chord.symbol
    roman = res.roman
    print(f"{input_symbol} -> {roman}")

# 出力例:
# Dm7 -> IIm7
# G7 -> V7
# Cmaj7 -> IM7
# A7(b9) -> VI7(b9)  <- 文脈からセカンダリードミナントとして解釈
# Dm7 -> IIm7
```

## 詳しい使い方

### 1. 転調を含む進行の解析

`annotate_progression` には、`ParsedChord` 単体だけでなく、`(ParsedChord, Key)` のタプルを渡すことができます。これにより、途中でキーが変わる進行を正しく解析できます。

```python
progression = [
    ("C", "C"),  # Key=C
    ("F", "C"),
    ("Dm7", "F"), # Key=F に転調
    ("G7", "F"),
    ("C", "F"),
]

# ParsedChordオブジェクトのリストを作成するヘルパー
parsed_sequence = [
    (ChordParser.parse(c), k) for c, k in progression
]

results = romanizer.annotate_progression(parsed_sequence)

for res in results:
    print(f"Key: {res.key_tonic} | {res.chord.symbol} -> {res.roman}")

# 出力例:
# Key: C | C -> I
# Key: C | F -> IV
# Key: F | Dm7 -> VIm
# Key: F | G7 -> II7   <- Key=F における G7 (II7) 
# Key: F | C -> V
```
> ※ `annotate_progression` の入力リスト内でタプルを使わなかったアイテムは、コンストラクタで指定した `default_tonic` が適用されます。

### 2. ハイブリッドコードと特殊な解釈

Chord Romanizerは、分数コードが単なる転回形なのか、機能的なハイブリッドコードなのかを自動判別します。

#### ハイブリッドコード (Functional Slash Chords)
例: **Key=C における `F/G`**
- これは `Dm7/G` や `G9sus4` の省略形として機能します。
- 解析結果 (`RomanizedChord`) には以下の情報が含まれます:
    - `roman`: `IV/V` (ベース指定のローマ表記)
    - `is_hybrid`: `True`
    - `alter`: `V9sus4` (機能的な解釈)

#### ブラックアダーコード (Augmented Triad over Bass)
例: **Key=C における `Eaug/D`**
- ホールトーンスケール由来の特殊なドミナントとして検出されます。
- 解析結果:
    - `is_hybrid`: `True`
    - `alter`: `D7(9,#11)` などの解釈が付与される場合があります。

### 3. 解析結果オブジェクト (RomanizedChord)

`annotate_progression` が返す `RomanizedChord` オブジェクトの主なプロパティは以下の通りです。

| プロパティ | 型 | 説明 |
| --- | --- | --- |
| `roman` | `str` | 最終的なローマ数字表記 (例: `IIm7`, `V7/VI`, `IV/V`) |
| `degree_root` | `str` | ルートのディグリー (例: `II`, `#IV`) |
| `degree_bass` | `Optional[str]` | ベース音のディグリー (転回形や分数コードの場合) |
| `is_hybrid` | `bool` | ハイブリッドコード（機能的分数コード）と判定されたか |
| `alter` | `Optional[str]` | ハイブリッドコードの場合の機能的なコード名解釈 (例: `V9sus4`) |
| `symbol_fixed` | `Optional[str]` | 文脈に合わせて異名同音を修正したコードシンボル (例: `Gb7` -> `F#7`) |
| `is_ii_v_start` | `bool` | ツーファイブ進行の起点(II)と判定されたか |
| `is_resolution_target` | `bool` | ドミナントモーションの解決先(I)と判定されたか |

### 4. オプション: 異名同音の簡略化

ダブルシャープ (`x` / `##`) やダブルフラット (`bb`) を回避したい場合、`simplify_accidentals=True` を指定します。

```python
# Key=G# (8 sharps)
# Leading Toneは通常 "Fx" (F##) ですが...
romanizer = Romanizer(default_tonic="G#", simplify_accidentals=True)

chord = ChordParser.parse("Fdim") # 本来 Fxdim (VII) のつもり
results = romanizer.annotate_progression([chord])

print(results[0].roman)
# -> "VIIdim" (度数は正しく VII と判定)

print(results[0].symbol_fixed)
# -> "Gdim" (F##dim ではなく、読みやすい Gdim にリスペルされる)
```

## ライセンス
[MIT License](LICENSE)
