Macを持たない環境で、iPhoneアプリとWindowsアプリを両輪で育てた10ヶ月分ではなく約2週間の記録(2026-07-04〜2026-07-22)
コピペ読み上げから始まり、共有・URL記事・PDF・Word・Siri・OCR・Windows版へと、入力経路と読み上げエンジンを一つずつ広げてきた歩み。
embedded.mobileprovision から実行時に解決する方式で突破した。PowerShell + WinForms + System.Speech(SAPI)によるゼロ依存GUI。インストール不要。貼り付け/クリップボード読込/.txt・.docx読込/グローバルホットキー Ctrl+Alt+R でどのアプリの選択文でも即読み上げ/読み上げ語のハイライト+追従スクロール/速さスライダー/声は自動判定(日本語=Haruka、英語=Zira)。
読み上げエンジンをSAPI(Haruka)からAivisSpeech Engine(ローカルHTTP・完全無料・外部送信ゼロ・localhost:10101)へ世代交代。SAPIはフォールバック兼英語声として残存。話者は「まお」「コハク」(各スタイル選択可)。日本語→Aivis/英語→SAPI Zira/Aivis不達時→SAPI Harukaへ自動フォールバック。
Invoke-RestMethod は charset 指定のない応答を ISO-8859-1 として読むため、AudioQuery の日本語が壊れ、そのまま送り返すとエンジンが 500 を返す。→ 応答をバイト列で受け取り自前で UTF-8 デコードして解決。SpeakProgress/SpeakCompleted を PowerShell から登録すると、読み上げ中にプロセスが終了コード2で強制終了する(try/catch 不可・イベントは一度も発火しない)。v1.0 のコードでも再現=既存の不具合。→ SAPI も Aivis と同じチャンクキューにし、State の100msポーリングで進める方式へ統一。副産物としてハイライトが両エンジンで文単位に揃った。入力経路が増えても、内部では共通のデータ形式に正規化してから読み上げエンジンへ渡す4層構造。
同じ「長文を聞く」目的でも、実現している機能とタイミングはプラットフォームごとに異なる。
| 機能 | iOS版 | Windows版 |
|---|---|---|
| テキスト貼り付け/コピペ読み上げ | ○ MVP1 v0.2.0 |
○ MVP8-a win v1.0 |
| 他アプリからの共有(Share Extension) | ○ MVP2 v0.3.2 |
記録なし |
| URL記事の本文抽出 | ○ MVP3 v0.4.0 |
記録なし |
| PDF読み上げ | ○ MVP4 v0.5.0 |
記録なし |
| Word(.docx)読み上げ | ○ MVP5 v0.6.0 |
○ MVP8-a win v1.0 |
| Siri / 音声での起動 | ○ Siri・App Intents MVP6 v0.7.0 |
○ グローバルホットキー Ctrl+Alt+R MVP8-a win v1.0 |
| OCR画像読み取り | 実機確認待ち MVP7 v0.8.0 |
記録なし |
| スキャンPDF自動OCR | ○ v0.9.0 |
記録なし |
| 保存した文章のライブラリ化 | ○ v0.7.0 |
記録なし |
| 読み上げエンジン | OS標準 + Azure AI Speech(F0無料枠、自動フォールバック) | SAPI(Haruka/Zira) → AivisSpeech(まお/コハク、ローカル0円) MVP8-a → MVP8-b win v2.0 |
| ハイライト表示 | 文タップジャンプ MVP1 |
読み上げ語ハイライト+追従スクロール → 文単位表示に変更 MVP8-a → win v2.0 |
| 速度調整 | 0.25x〜4x(Azureはprosody×再生レート) v0.4.1 |
速さスライダー → speedScale 0.5〜2.0 MVP8-a → win v2.0 |
| 読み方辞書 | ○ 日本語音声のときだけ適用 | ○ 日本語音声のときだけ適用 |
2週間の開発で繰り返し効いてきた、次のプロジェクトにも持ち越すべき学び。
v0.4.4の「戻る」で永久フリーズする不具合は、実機ハングレポート(.ips)を取得して初めて「ナビバー大タイトル × TextEditorのレイアウト無限ループ」という真因にたどり着けた。当てずっぽうの修正より先に証拠を取る。
Windows PowerShell 5.1は.ps1をBOMなしだとANSIと誤読し日本語が文字化けする。以降.ps1はUTF-8 BOM必須、新規.batファイルは純ASCIIのみで統一するルールにした。
System.Media.SoundPlayerは再生の途中停止ができず、止めようとするとプロセスごと落ちる。win v2.0ではWAVを一時ファイル化しWPF MediaPlayerで再生、WinFormsタイマーで終了を検知する設計に切り替えた。
無料Apple IDとAltStoreの組み合わせではApp Group IDが固定されない。embedded.mobileprovisionから実行時に解決する方式で、Share ExtensionとApp本体のデータ共有を成立させた。
カタカナ読みの辞書を英語音声にそのまま当てると発音が崩れる。「日本語音声のときだけ適用」に修正し、iOS・Windows両方に反映した。
v2.0で英語読み上げ中にプロセスが強制終了したとき、v1.0のコードを取り出して同じ手順を流したら同じように落ちた。新しく書いた部分ではなく、SAPIのイベント登録という前からあった箇所が原因だった。犯人を推定する前に、旧版で再現するかを試す。
PowerShell 5.1はcharset指定のないJSON応答をISO-8859-1として読む。壊れた日本語をそのまま送り返した結果が「500 Internal Server Error」で、エラーメッセージだけ見ても文字コードが原因とは分からない。日本語を通すHTTPは、必ずバイト列で受けて自分でUTF-8デコードする。
方針としてOS標準TTS+正規サービスのみを採用。Azure Dragon HDはJapan East非対応・F0無料枠対象外・prosody非対応で見送り、ElevenLabsは1冊あたり約¥4,500で見送り、Windows版はローカル0円のAivisSpeechを採用した。