前回のエントリでは 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 を聞いて、アバウトな依頼を何度かしました。
もう少し滝の音に近づけてください
もっと滝の音に近づけてください。
farの方は音が篭りすぎています。
で、最終的な synth.rs は「滝の音は無数の水しぶきと気泡の集合」という考え方で、
- 180Hz〜7kHz を14帯域に分けて、帯域ごとに独立したショットノイズで振幅変調したノイズ(ザーッ、バシャバシャ)
- 控えめな下地のノイズ(低域は盛らない。盛ると車になる)
- 毎秒数百〜千数百個の気泡の共鳴音。浮上しながらピッチが上がるのが「水らしさ」の決め手だとか
- 短めの残響と、距離に応じたローパス
という構成になっています。気泡の音は 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),
});
}
へえ、そうなんすね、って感じ。ごめんなさい。
雑感
- 適当で感覚的なコメントでもそれっぽく対応してくれて神。私だったらキレるわ
- rust コードの勉強になるかも?と思ったけど、そんなことなかった
- Claude Code でやっても同じものは出来るだろうけど、携帯アプリから依頼するだけでアプリが完成するって体験が強い
- 調整の結果、滝っぽく聞こえる音になったけど、あんまり癒されなかった。もともと滝の音で癒されるタイプの人間じゃないのかも?