Fish Audioの無料APIで自分の声を合成し、音声透かしをAudioSealとWavMarkで調べた記録(Irodori-TTSとの比較)

開発misc-dev

Fish Audioの無料APIで自分の声を合成し、音声透かしをAudioSealとWavMarkで調べた記録(Irodori-TTSとの比較)

Google タスクの今日の欄に「TTS を試す」が残っていた。 前日の 講座ナレーションを自分の声で作る TTS の調査 の続きで、今日は実際に音を出す番だった。

Claude Code にタスクを読ませると、Fish Audio の Drama 3 を試す項目が見つかった。 準備までは進めてもらったが、先へ進むには私が2点を決める必要があり、そこで止まった。

11月30日まで無料という告知

決める前に、Fish Audio の無料 API の告知記事 を Claude Code に渡し、どれだけ無料になるのかを聞いた。

答えは、ほぼ使い放題だった。 s2.1-pro-free というモデル名を指定すれば、2026年11月30日まで、文字数と回数の上限なしで無料で使える。 ただし、フェアユースポリシーの範囲内という条件が付く。 無料版の中身は有料版と同じ S2.1 Pro だ、とも Claude Code は説明した。

私が API キーを 1Password に登録し、Claude Code に叩かせた。 結果はモデルで分かれた。

モデル結果
s2.1-pro-free(無料)通った
drama-3-preview(Drama 3)API クレジット不足の HTTP 402 で弾かれた

この時点では自分の声を送っておらず、既製の声で試しただけである。 11月末まで無料なら面白い、と思った。 自分の声を送ることを私が了承すると、Claude Code は合成スクリプトを書き、無料モデルで1回目(23文)を流した。

2回目の合成が 1Password の前で止まる

2回目は、合成に入る前に止まった。 1Password からキーを読み出す op read が、2回続けて authorization timeout で失敗したのである。

10:12 の1回目は通っていた。 その後に 1Password アプリがロックされたのだろう、というのが Claude Code の見立てだった。 同じエラーが2回続いたので、プロジェクトのルールどおり issue に記録させた。

結局、承認ダイアログを出すために Claude Code が合成を流し直し、ダイアログが通ってから2回目も最後まで進んだ。 グリッド検査も通り、聞き比べページが更新された。

聞き比べて浮かんだ透かしへの疑問

聞き比べると、Irodori-TTS のほうが私の録音した声に近く、Fish のほうが AI 合成に近く聞こえた。

そこで引っかかったのは、画像生成では勝手に入る識別子のことだった。 AI の音声にも、合成だと分かる印が入るのだろうか。

Claude Code に調べさせると、足元から答えが出てきた。 手元の Irodori の環境に SilentCipher が入っていて、合成のたびに「IRDTS」という識別子を埋め込む作りだった。 合成したままの音声からは、IRDTS がはっきり読み出せた。 講座の本番音声は速度を変えてあり、その加工の後では読み出せなかった。 Fish の音声については、入っているとは確認できなかった。

調べた結果には Gemini の話も含まれていて、それで思い出した。 Gemini は Google のサービスなので、アカウントを BAN されたときなどを考えると面倒だから避けよう、と前に話していたのだった。 その理由も、Claude Code にメモへ書き足させた。

今回は Fish の無料版が普通に使えるので、そちらでやるか、とその場では考えた。 耳は Irodori に寄っているのに、条件は Fish に寄っている。

検出器を知らなければ透かしは確かめられない

Claude Code の説明によると、透かしの有無は原則として、検出する方法(検出器と、多くの場合は秘密の鍵)を知らないと確かめられない。 耳で聞こえず、統計的にも目立たないように埋め込むのが、透かしの設計目標だからである。 Irodori の透かしを読み出せたのも、Irodori がソニーの SilentCipher を使っていて、その検出器が公開されているからだった。

私は AudioSeal と WavMark も試すよう頼んだ。

Claude Code は AudioSeal(Meta)と WavMark の2つの検出器を当てた。 検出器が働くかを確かめるため、自分で透かしを入れた音声(陽性)と、私の録音(陰性)も一緒に判定した。

処理は10分を超えて、バックグラウンドに回った。 途中で torch の読み込みにつまずき、issue に記録させた。 GPU 版の torch で読み込めるようになってから、検出器を GPU で動かすようにスクリプトを直してもらった。

全件の判定が終わった結果は次のとおり。

音声AudioSealWavMark
Fish出なかった出なかった
Irodori(合成したまま)出なかった出なかった

Irodori が使っているのは SilentCipher なので、Irodori から出ないのは想定どおりである。

なぜ2回目を作ったのか

ここで、なぜ2回目を作ったのかが分からなくなり、Claude Code に聞いた。

Fish で同じ文をもう一度作ると、どのくらい違う音になるか(生成のたびの結果のぶれ)を確かめるためだった。 Google タスクの手順6に「生成のたびの結果のぶれを記録する」と書いてあり、それに合わせて2回作ったという。 Fish の API にはシードを指定する項目がない。 そのため、同じ台本と同じ参照音声で頼んでも、毎回違う音が返ってくる。

そう聞いて、Irodori のほうが気になった。 Irodori は、狙った語だけシード値を変えて音を変え、ほかの部分は全く変えない、ということができるのか。 だとしたら、切り取って繋げているのか。

答えは、語単位ではなく文単位だった。 文ごとに作った音声をつなげている点は、私の推測どおりだった。 ただし切り取っているわけではなく、切れ目は文と文のあいだの無音にしか来ない。

Fish に透かしはあるのか、もう一度調べる

検出器2つで出なかったからといって、入っていないとは言えない。 私は Fish が透かしを入れていないかを、もう少し深く検索するよう頼み、Claude Code からサブエージェントに任せてもらった。

報告が届くと、要となる2点(運営会社と、ファイルにメタデータが入っていないこと)を Claude Code が自分でも確かめた。 結論は次のとおり。

  • メタデータの目印は入っていないと言える
  • 耳で聞こえない透かしは、公表も検出もなく「不明(入っていない寄り)」
  • 確実に知るには、Fish Audio に直接問い合わせるしかない

透かしが見つからないという材料が、Fish の側に一つ増えた。 この日はこのあと、Irodori で読み替えが必要だった文を Fish に漢字のまま読ませる比較へ進んだ。

学び

  • 音声透かしは、検出器(と多くの場合は鍵)を知らないと確かめられない。Irodori の IRDTS を読み出せたのは、SilentCipher の検出器が公開されていたからだった
  • Fish の API にはシード指定がなく、同じ台本と参照音声でも毎回違う音が返る。Irodori の差し替えは語単位ではなく文単位で、切れ目は文と文のあいだの無音に来る
#TTS#ボイスクローン#Fish Audio#Irodori-TTS#音声透かし#1Password