前回のエントリでは Claude Cowork にスライドを作らせた話を書きましたが、今回はプログラムを作ってもらった話。
お題は「滝の音を鳴らすアプリ」です。なぜなら、滝の音で癒されたいからです。

Cowork は公式的には「コーディング以外の知的作業向け」というポジションらしい[要出典]のですが、まあ普通にプログラムも作れるんじゃないかと。

というわけで、Claude Cowork の利用事例のひとつとして、その顛末を残しておくエントリ。
※内容は 2026年9月のものです。

Claude Cowork とは

ざっくり言うと、Claude Desktop アプリに付いている「フォルダを渡して作業を丸投げする」タブです。Chat、Code と並んで Cowork というタブがあって、そこでフォルダを指定して依頼すると、その中のファイルを読み書きしながら作業してくれる。
有料プラン(Pro 以上)で使えて、最近は Web やスマホからも使える。

Claude Code との違いは、ターミナルがいらないことと、渡したフォルダの外には出ないこと、あたり。Claude Code 用に育てた CLAUDE.md やスキルはそのままでは引き継がれないそうです。使い分けは下の参考にある Qiita の記事とかを参照。

最近「Cowork」という表記が消えた

頼んだこと

Cowork のタブで

滝の音が癒し音声として流行っています。
rust などのプログラミング言語を用いて、リアルタイムにPCMで滝の音相当の音声を生成・再生するアプリを実装できますか?

と入力して、しばらく待つと、Cargo プロジェクト一式が zip で出力されました。
中身はこれだけ。

waterfall/Cargo.toml
waterfall/Cargo.lock
waterfall/src/main.rs
waterfall/src/synth.rs

依存は cpal と anyhow の2つのみ。cpal はクロスプラットフォームのオーディオ I/O ライブラリで、macOS だと CoreAudio を叩くらしい。

https://github.com/yosiopp/synth_waterfall

できたもの

--help はこんな感じ。

waterfall - 滝の音をリアルタイム生成して再生します

USAGE:
  waterfall [OPTIONS]

OPTIONS:
  -v, --volume <0..1>      音量            (default 0.6)
  -i, --intensity <0..1>   水量・飛沫の強さ (default 0.6)
  -d, --distance <0..1>    滝までの距離    (default 0.3, 大きいほど遠く柔らかい音)
  -w, --water <0..1>       水音(泡立ち・ゴボゴボ)の量 (default 0.4)
      --wav <FILE>         再生せず WAV ファイルに書き出す
      --seconds <SEC>      WAV 書き出し秒数 (default 30)

再生中は標準入力で操作できます:  v 0.4 / i 0.9 / d 0.7 / w 0.8 / q

頼んでないのに WAV 書き出しまで付いてきた。すげー。

音を滝に寄せるまで

で、一発で滝の音になったかというと、そうでもなくて。
Cowork 上で再生可能な wav を聞いて、アバウトな依頼を何度かしました。

take 2:
雨の音っぽく聞こえますね。
もう少し滝の音に近づけてください
take 3:
機械音に近づきました。車が走っているように聞こえます。
もっと滝の音に近づけてください。
take 4:
nearは良い感じです。強いていうなら水の音を足しても良いかもしれません。パラメタで調整できるようにしてください。
farの方は音が篭りすぎています。

で、最終的な synth.rs は「滝の音は無数の水しぶきと気泡の集合」という考え方で、

という構成になっています。気泡の音は Minnaert 共鳴というものらしい。(コメントにそう書いてある)

気泡を1個生やすところはこんな感じ。

fn spawn_bubble(&mut self) {
    // 500Hz〜4kHz。小さい泡(高い音)ほど多い
    let u = self.rng.uniform();
    let freq = 500.0 * (8.0f32).powf(u.sqrt());
    let len_s = (0.004 + 0.02 * (1.0 - u)) * (0.6 + 0.8 * self.rng.uniform());
    // 浮上中のピッチ上昇をはっきりめに(15〜40%)=「水らしさ」の決め手
    let rise = 1.15 + 0.25 * self.rng.uniform();
    let n = len_s * self.sr * 3.0;
    self.bubbles.push(Bubble {
        phase: 0.0,
        freq,
        chirp: rise.powf(1.0 / n),
        env: 1.0,
        decay: (-1.0 / (len_s * self.sr)).exp(),
        gain: 0.03 + 0.12 * self.rng.uniform().powi(3),
    });
}

へえ、そうなんすね、って感じ。ごめんなさい。

雑感

参考