Nostrの音楽アプリをぼんやり構想してみる
Nostr のトラフィックと時間をともにできるアプリを作ったら面白いのではないかと思い、ぼんやり構想しています。
Nostr ってなあに?
さて、まず読み方がわかりません。じつは、決まった読み方がないのです。ノストルでも、ノスターでも、お好きな読み方をあててみてください。
Nostr は、2022 年に fiatjaf 氏が提唱した、新しい分散型 SNS のプロトコルです。
- プロトコルとは、コンピュータが互いにコミュニケーションをとるための共通言語のようなものです。
- 分散型 SNS は、従来の SNS のように特定の会社が管理するのではなく、メールのように、様々なサーバーが独立して運営できる仕組みです。
Nostr では、 「イベント」 と呼ばれるデータを使ってやり取りします。 例えば、あるユーザーが投稿すると、それはイベントとして Nostr のネットワークに流れます。
- イベントは 「リレー」 と呼ばれるサーバーに送られ、保存・配信されます。 リレーは世界中にたくさんあり、ユーザーは自分の好きなリレーを選んで接続できます。
- イベントには電子署名が施されます。 これにより、誰がイベントを作成したのか、内容が改竄されていないかを証明できます。
Nostr は、検閲に強く、ユーザーが自由に発信できる SNS を目指しています。まだ新しい技術ですが、すでにさまざまに応用されていて、掲示板、動画サイト、フリマアプリ、音楽配信サイトなどなど……たくさんのアプリが作られています。そして、それらのアプリすべてでひとつのアイデンティティを使うことができる所も大きな特徴です。今後の発展が期待されています。
トラフィックと時間をともにする
念頭には Bloom と Project audio for Github があります。
Bloom は iOS 向けの作曲アプリです。シンプルな画面と感覚的な操作が特徴で、眺めているだけでとても心地よいです。
Project audio for Github は Github 上で行われている作業を音楽に変換するアプリです。画面は Bloom によく似ていますが、操作できるスイッチなどはありません。偶然性の音楽とでも言うのでしょうか、Github のトラフィックがリアルタイムで音に変換されます。
さて、なんとなく作りたいものが見えてきました。Nostr の特定のリレーサーバーからイベントをストリーミングして、いいかんじに音に変換するアプリをつくりたいです。
では、どうすればいいでしょうか。
楽しい音を奏でる
さて、義務教育時代の記憶を掘り起こしてみましょう。なんということでしょう、義務教育がなければ人を楽しませることもできないとは。
音の三要素というものがありましたね。
- 音の高さ(周波数)
- 音の大きさ(振幅)
- 音の音色(波形)
音の大きさは、そのままイベントのデータの大きさで良いような気がします。音色は……今はまだ決め打ちでいいでしょうか。
さて、問題は音の高さです。
ハッシュ値を使うのはどうでしょうか?イベントにはイベントのハッシュ値が含まれます。
ハッシュ値とは、そのデータから決定論的に算出される、逆算できない値のことです……といってもなんのこっちゃという感じですね。
割り算の余りを考えてみましょうか。42 割る 5 の余りはいくつでしょうか。2 ですね。
さて、2 という値だけ与えられたときに、もとの 42 という数字を予測することはできるでしょうか。割る 5 の余りを求めていることくらいは知っていることにしましょう。
5 で割ったとき 2 が余る数ですから、7 でしょうか。12 かもしれません。そうですね、ひとつに絞ることはできませんね。
このように、決定論的に計算をしたからといって、必ずもとの値が逆算できるとは限りません。こういった特徴を持っている数式が、一方向関数……特に暗号分野で用いられるのがハッシュ関数です。ハッシュ関数を使って求めた値がハッシュ値ですね。
話がそれました。
というわけで、イベントに含まれるハッシュ値はイベント固有の、ほぼランダムなものですから、これをもとにして音の高さを決めればいいような気がします。
しかし、単純にそうしていいのでしょうか?それではランダムにピアノを叩くのと変わりません。現代音楽ではランダムに音を鳴らすこともあるようですが、あれは私には高尚すぎます。
制約が必要です。
和声音
調べてみると、楽曲に課される制約のひとつにコードなるものがあるようです。コードは心地よく感られるひとまとまりの和音で、これに従属する音を和声音というようです。
ゆる音楽ラジオという Youtube の音楽解説チャンネルを見ると、この和声音をド・ミ・ソと決め打ちしたうえで作曲を行う手法が出てきたので、これに従うことにします。
経過音
和声音から非和声音を経過し和声音へ至る音です。つまり、ドがあったとき、レを経過し、ミへと至るような音です。音階は飛ばさず、ひとつずつ移動します。
刺繍音
和声音から、ひとつ音階がずれた非和声音に移動し、もとの和声音に戻る音を刺繍音というようです。ド→シ→ドやド→レ→ドのような音です。
倚音
非和声音から始まり、すぐに和声音に戻る音のことを倚音というようです。
ほかにもいろんな要素が紹介されていましたが、今回作るのは始まりもなければ終わりもない、しかも予測できないタイミングで予測できない大きさの音が鳴るものですから、いまは気にしなくてもよいでしょう。
実装を考える
さて、先程見てきた制約に従い、音の高さを決めたいです。
問題は、1 イベントに 1 音が対応するところです。これを考えると、過去に鳴らした音を記憶して、今鳴らす音を決定する処理が良さそうです。
- 直前が和声音であったとき、ひとつ音階がずれた非和声音を鳴らす(経過音か刺繍音が始まる)。
- 直前が和声音であったとき、偶然で決められた非和声音を鳴らす(倚音が始まる)
- 直前が非和声音であったとき、ひとつ音階がずれた和声音を鳴らす(上下のどちらにずれるかで、経過音か刺繍音かが決まる。もしくは、倚音が終わる)。
ひとまずルールはこれでいいでしょうか。偶然性の伴う部分はハッシュ値をもとにすればいいでしょう。問題は、経過音・刺繍音・倚音の割合です。単純に 3 等分していいのでしょうか?既存の楽曲を調べていく必要がありそうです。でもそんなことしてたら大変だな。やっぱり 3 等分しようかな。
じつは、このほかにも裏でベースやコード進行について検討したりしていました。ベースの生成にはこのアルゴリズムが使えそうだとか、コード進行にはある程度厳密なルールが用意されているらしいとか、そういう話がでてきましたが、ちょっと大変すぎるのでやめました。
おおむねアイデアがまとまってきたので、また時間があるときにでも作ってみようと思います。ではまた。バハハイ。