Metadata-Version: 2.4
Name: chenpi
Version: 0.2.0
Summary: Read DS/3DS capture boards (Loopy DS, Optimize Old 3DS) as OpenCV/numpy images on Windows
Author: Lizz
License-Expression: MIT
License-File: LICENSE
License-File: LICENSES/cc3dsfs.txt
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Multimedia :: Video :: Capture
Classifier: Development Status :: 3 - Alpha
Requires-Dist: numpy>=1.26
Requires-Dist: opencv-python>=4.9
Requires-Dist: sounddevice>=0.5.6 ; extra == 'audio'
Requires-Dist: pyvirtualcam>=0.15.0 ; extra == 'virtualcam'
Requires-Python: >=3.12
Provides-Extra: audio
Provides-Extra: virtualcam
Description-Content-Type: text/markdown

# chenpi

**chenpi** (陳皮) は、DS / 3DS 用キャプチャ機器の映像・音声を、公式ビューアやウィンドウキャプチャを使わずに
numpy / OpenCV の画像として直接取り込むための Windows 用ライブラリです。
`cv2.VideoCapture` と同じ `read()` で読めるので、OpenCV 前提のコードにそのまま渡せます。
[cc3dsfs](https://github.com/Lorenzooone/cc3dsfs) (MIT License) の処理を Python に移植しています。

| 機種 | 映像 | 音声 | 備考 |
|---|---|---|---|
| 新型 Loopy DS キャプチャ (USB Type-C 版) | 256x192 × 2 画面 / 60fps | あり | |
| Optimize 3DS キャプチャ (Old 3DS 用) | 400x240 + 320x240 / 60fps | あり | 公式ソフトのプロダクトキーが必要 |

Optimize の New 3DS 用 / 2DS 用、RGB888、3D 表示、Loopy 製 3DS キャプチャには未対応です。

## 準備

1. **ドライバ**: 各機器の公式ソフトに付属するドライバをそのまま使います (公式ソフトが動く環境なら導入済み)。
   - Loopy DS: FTDI の D2XX ドライバ
   - Optimize 3DS: 公式ドライバ (NSTDUSB3)
   - Zadig などで WinUSB に差し替えると動きません。
2. **インストール**

   ```powershell
   uv add "chenpi[audio,virtualcam]"     # 別のプロジェクトから使う場合 (pip install でも可。音声・仮想カメラが不要なら [] は省略)
   uv sync                               # このリポジトリで開発する場合
   ```

3. **ファームウェアの取得**: 基板に書き込むファームウェアは同梱していないので、cc3dsfs から取得します
   (理由は[ファームウェアについて](#ファームウェアについて))。ビューアは、無ければ取得してよいか尋ねます。

   ```powershell
   uv run scripts/fetch_firmware.py   # %LOCALAPPDATA%\chenpi\firmware に保存
   ```

4. **Optimize 3DS のプロダクトキー**: `--key` か環境変数 `OPTIMIZE_3DS_KEY` で渡します (カンマ区切りで複数可)。

   ```powershell
   setx OPTIMIZE_3DS_KEY "XXXX-XXXX-XXXX-XXXX-XXXX"   # VS Code / ターミナルを開き直すと有効
   ```

公式ソフトや cc3dsfs とは同時に使えません。先に閉じてください。

## ビューアで試す

```powershell
uv run chenpi-view --list                 # 接続されている機器の一覧
uv run chenpi-view                        # 見つかった機器を表示 (q で終了)
uv run chenpi-view --device 3ds --audio   # 機種を指定し、音声も再生 (+ / - キーで音量)
uv run chenpi-view --layout horizontal --scale 3
```

| オプション | 内容 |
|---|---|
| `--device auto\|ds\|3ds` | 機種 (既定 `auto`: DS → 3DS の順に探す) |
| `--key` | Optimize 3DS のプロダクトキー |
| `--layout vertical\|horizontal\|top\|bottom` | 画面の並べ方 |
| `--scale` | 表示の拡大率 (既定 2) |
| `--audio` / `--volume` / `--audio-latency` | 音声の再生 / 音量の倍率 / 出力バッファ (秒) |

## ライブラリとして使う

### OpenCV と同じように読む

```python
from chenpi import open_capture

with open_capture("auto", layout="vertical") as cap:   # "ds" / "3ds" も指定できる
    ok, frame = cap.read()        # BGR uint8。vertical なら DS は 256x384、3DS は 400x480 (下画面の左右は黒帯)
    audio = cap.read_audio()      # 前回以降の音声 int16 (N, 2) [L, R]
    chunks = cap.read_audio_chunks()   # 受信時刻付きで受け取る場合: [AudioChunk(samples, captured_at), ...]
```

機種ごとのクラス (`LoopyDSCapture` / `Optimize3DSCapture`) を直接使うこともできます。

API の一覧・frame の大きさ・例外・注意点は [src/chenpi/USAGE.md](src/chenpi/USAGE.md) にまとめてあります。
このファイルはパッケージにも入るので、chenpi を使う別のプロジェクトでは、その CLAUDE.md などに次のように書いておくと、
コーディングエージェントが正しい使い方を参照できます。

```markdown
- キャプチャには chenpi を使う。使い方は `.venv/Lib/site-packages/chenpi/USAGE.md` を読むこと。
```

### 機器の一覧から選んで開く (GUI 向け)

```python
from chenpi import list_devices, open_device

infos = list_devices()                # 機器には触らずに一覧だけ返す (ファーム書き込みなどはしない)
for info in infos:
    print(info, info.available)       # 例: "Optimize Old 3DS [使用中]" False
cap = open_device(infos[0], key=["XXXX-...", "YYYY-..."])   # 3DS は保存してあるキーを全部渡せば合うものを使う
print(cap.serial)                     # 3DS ならデバイス ID。キーとの対応を保存しておくとよい
```

- `info.status` は `ready` / `in_use` (他のプログラムが使用中) / `replug` (公式ソフト使用後で USB の抜き差しが必要)。
- Optimize 3DS のデバイス ID は開くまで分からないので、一覧では `info.id` が `None` です。
  挿した直後は「未初期化」と表示されます (Old 3DS 用 / New 3DS v2 用 / 2DS 用の区別は付きません)。
- Optimize を 2 台つないでいても、キーの合う空いている方が開きます。
- 同じ機器を 2 つのプログラムで同時に開くことはできません (cc3dsfs との間でも)。
- 使用中の Loopy DS は、ID (シリアル) が大文字で表示されます (Windows の記録による)。比べるときは大文字小文字を区別しないでください。

### 音声

- DS・3DS とも `SAMPLE_RATE` (≒ 32728.5 Hz) のステレオ int16 です。
- `read_audio()` は待たずに、溜まっている分を全部返します (読まれない分は約 2 秒で古い順に捨てます)。
- `read_audio_chunks()` は同じ音声をフレームごとに受信時刻 (`captured_at`, `time.monotonic()`) 付きで返します。
  `read_audio()` と同じ溜まりから取り出すので、どちらか一方を使ってください。
- 取り出した音声は生の値です。PC で鳴らすときは `AudioPlayer` (extra `audio`) に渡し、音量はそちらで変えます。

  ```python
  from chenpi import AudioPlayer

  with AudioPlayer(volume=0.8) as player:   # 溜めてから鳴らすので途切れにくい
      player.write(cap.read_audio())
      player.volume = 0.5                   # 再生だけにかかる。GUI のスライダーなら value / 100 など
      player.muted = True
  ```

### GUI に組み込むときの注意

- **ファームウェアが無いとき**は `FirmwareMissing` (足りないファイル名は `e.names`) になります。
  勝手にダウンロードせず、利用者に確認してから取得してください。

  ```python
  from chenpi import FirmwareMissing, download_firmware, open_device

  try:
      cap = open_device(info, key=keys)
  except FirmwareMissing as e:
      if ask_user(f"{e.names} を cc3dsfs から取得しますか?"):
          download_firmware()
  ```

- **CPU 使用率**: 毎フレーム OpenCV で拡大や表示をするなら、アプリの最初で `cv2.setNumThreads(1)` を呼んでください。
  OpenCV は小さな処理も複数スレッドに分け、その後スレッドが空回りするため、ビューアでは 1 コアの約 9 割 → 約 3 割に下がりました。
  プロセス全体の設定なので、ライブラリ側では変えていません。
- `read()` は新しいフレームが来るまで待つので、GUI のメインスレッドではなく別スレッドで回してください。
- 機器を切り替えるときは、先に `cap.release()` を呼んでください。
- 受信中に USB が抜かれると、`read()` が `(False, None)` を返し、`cap.isOpened()` が False になります (固まりません)。

## 仮想カメラ

OBS Studio (OBS Virtual Camera) が入っていれば、普通の Web カメラとして他のアプリから使えます。
OBS 側の「仮想カメラ開始」は止めておいてください (同時には使えません)。

```powershell
uv run chenpi-virtualcam --device 3ds   # --layout / --scale / --audio / --key もビューアと同じ
```

```python
import cv2
cap = cv2.VideoCapture(3, cv2.CAP_DSHOW)  # 番号は環境による (OBS Virtual Camera の番号)
```

仮想カメラには音声は乗りません (OBS Virtual Camera は映像のみ)。

## 機種ごとの注意

### Optimize 3DS

- 公式ソフトを使った後は、USB を抜き差ししてから開いてください (公式ソフトが別のファームウェアを書き込むため)。
- 3DS 本体の「本体設定 → その他の設定 → サウンド」は **ステレオ** にしてください。
  サラウンドのままだと、スピーカー用のサラウンド処理 (中音域を左右逆位相で混ぜる) がかかった音が届き、PC で聞くとこもって聞こえます。
- 本体の音量スライダーはキャプチャの音には効きません。`AudioPlayer.volume` か PC 側で調整してください。

### Loopy DS

- DS 本体の電源が切れていると、開くことはできますが映像が届きません (ビューアは「信号待ち」と表示します)。

## ファームウェアについて

キャプチャ基板に毎回書き込むファームウェア (と Optimize のキー計算用テーブル) は、このライブラリに **同梱していません**。
これらは cc3dsfs で公開されているファイルですが、cc3dsfs の MIT ライセンスの対象外で、著作権は各メーカーにあります
(Loopy DS 用は Loopy 社提供、Optimize 用は non-standard)。利用者自身が cc3dsfs から取得してください。

- 取得元は動作確認した cc3dsfs のコミットに固定していて、SHA-256 が合わないファイルは保存しません。
- 探す場所は、引数 `firmware_dir` → 環境変数 `CHENPI_FIRMWARE_DIR` → `./firmware` → このリポジトリの `firmware/` →
  `%LOCALAPPDATA%\chenpi\firmware` の順です。

## 開発

```powershell
uv sync
uv run pytest   # 実機不要。ファームウェアが無い環境では、それを読む数件のテストはスキップされる
```

GitHub Actions では、Windows 上でファームウェアを取得してからテストを回します (`.github/workflows/test.yml`)。

## ライセンス

MIT License ([LICENSE](LICENSE))。
cc3dsfs の処理を移植しているため、cc3dsfs のライセンス表示を [LICENSES/cc3dsfs.txt](LICENSES/cc3dsfs.txt) に含めています。
ファームウェアは上記のとおり同梱していません。
