chenpi
chenpi (陳皮) は、DS / 3DS 用キャプチャ機器の映像・音声を、公式ビューアやウィンドウキャプチャを使わずに
numpy / OpenCV の画像として直接取り込むための Windows 用ライブラリです。
cv2.VideoCapture と同じ read() で読めるので、OpenCV 前提のコードにそのまま渡せます。
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 キャプチャには未対応です。
準備
-
ドライバ: 各機器の公式ソフトに付属するドライバをそのまま使います (公式ソフトが動く環境なら導入済み)。
- Loopy DS: FTDI の D2XX ドライバ
- Optimize 3DS: 公式ドライバ (NSTDUSB3)
- Zadig などで WinUSB に差し替えると動きません。
-
インストール
uv add "chenpi[audio,virtualcam]" # 別のプロジェクトから使う場合 (pip install でも可。音声・仮想カメラが不要なら [] は省略) uv sync # このリポジトリで開発する場合
-
ファームウェアの取得: 基板に書き込むファームウェアは同梱していないので、cc3dsfs から取得します (理由はファームウェアについて)。ビューアは、無ければ取得してよいか尋ねます。
uv run scripts/fetch_firmware.py # %LOCALAPPDATA%\chenpi\firmware に保存
-
Optimize 3DS のプロダクトキー:
--keyか環境変数OPTIMIZE_3DS_KEYで渡します (カンマ区切りで複数可)。setx OPTIMIZE_3DS_KEY "XXXX-XXXX-XXXX-XXXX-XXXX" # VS Code / ターミナルを開き直すと有効
公式ソフトや cc3dsfs とは同時に使えません。先に閉じてください。
ビューアで試す
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 と同じように読む
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 にまとめてあります。 このファイルはパッケージにも入るので、chenpi を使う別のプロジェクトでは、その CLAUDE.md などに次のように書いておくと、 コーディングエージェントが正しい使い方を参照できます。
- キャプチャには chenpi を使う。使い方は `.venv/Lib/site-packages/chenpi/USAGE.md` を読むこと。
機器の一覧から選んで開く (GUI 向け)
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) 付きで返します。captured_atはtime.perf_counter()の値なので、比べる時刻もtime.perf_counter()で取ってください (0.2.0 まではtime.monotonic()でした)。read_audio()と同じ溜まりから取り出すので、どちらか一方を使ってください。 -
映像の受信時刻は、
read()の直後にcap.frame_captured_atで読めます (同じtime.perf_counter()の値で、 同じフレームの音声のcaptured_atと一致します)。read()の戻り値は cv2 と同じ(ok, frame)のままです。 -
取り出した音声は生の値です。PC で鳴らすときは
AudioPlayer(extraaudio) に渡し、音量はそちらで変えます。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) になります。 勝手にダウンロードせず、利用者に確認してから取得してください。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 側の「仮想カメラ開始」は止めておいてください (同時には使えません)。
uv run chenpi-virtualcam --device 3ds # --layout / --scale / --audio / --key もビューアと同じ
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の順です。
開発
uv sync
uv run pytest # 実機不要。ファームウェアが無い環境では、それを読む数件のテストはスキップされる
GitHub Actions では、Windows 上でファームウェアを取得してからテストを回します (.github/workflows/test.yml)。
ライセンス
MIT License (LICENSE)。 cc3dsfs の処理を移植しているため、cc3dsfs のライセンス表示を LICENSES/cc3dsfs.txt に含めています。 ファームウェアは上記のとおり同梱していません。
Metadata
Release files for chenpi 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| chenpi-0.3.0.tar.gz | 40.1 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| chenpi-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 87.8 kB
Release files / chenpi-0.3.0.tar.gz
| Download URL | chenpi-0.3.0.tar.gz |
|---|---|
| Size | 40.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1292f0288d93a08179501264ad7b12521c0286c03f96c60d6afc5840df66c413
|
|
BLAKE2b-256 checksum How to use checksums |
7a8d455967f6ccfcfc7e95013c66530224d443f25913dfb022305e33ad7a215f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / chenpi-0.3.0-py3-none-any.whl
| Download URL | chenpi-0.3.0-py3-none-any.whl |
|---|---|
| Size | 47.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
afad62f5f4a4a8e73e5cc42abe299d248c7650665bd8901efc1013ba3e1ca076
|
|
BLAKE2b-256 checksum How to use checksums |
e0f2b94e0ed3bf90189979f3d42fd22e5265355f6110658ead1e9e55e39b7703
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for chenpi 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.