4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Computer SocietyAdvent Calendar 2024

Day 9

【失敗談】ポエトリーリーディングのリアタイ自動生成ができなかった話【Computer Society Advent Calendar 2024】

Last updated at Posted at 2024-12-08

本記事でわかること

  • レイテンシはいつだって付きまとう
  • 変動する誤差は難しい
  • 諦めることも肝心

0. はじめに

はじめまして。1010mark(てんてんまーく)と申します。
本記事はComputer Society Advent Calendar 2024 9日目の記事となっています。KCSは、Computer Societyという慶應義塾大学の公認サークルです。このアドベントカレンダーでは、サークル員が記事を書いています。分野の垣根を超えた様々な記事がありますので、ぜひご覧ください。

8日目「矢上キャンパスにも一際の花(クリスマスツリー)」

この記事

10日目「何か書くcar」

ちなみに俺が一番気になっている記事は最終日の「入水しました!!」(記事執筆時点仮タイトル)です。

さて、Tidal Cyclesをご存知ですか?ご存知でなければ、以下の動画を見てみるのが一番早いです。1秒だけでもいいのでクリックしてご視聴ください。

Tidal Cyclesはリアルタイムに音楽を生成することができるツールの一つです。もし興味があれば、以下の記事を参考に触ってみるのが早いです。
  • 公式ドキュメント - 環境構築はこれが一番参考になります。各種OSに対応しており、導入も簡単です。Windowsに関してはコマンドライン2行で構築できます。
  • はじめてのTidal Cycles - 実際に手を動かしながらTidal Cyclesを学べます。

さて、このTidal Cyclesは様々な面白い機能を持っています。その一つがOSCです。

OpenSound Control(OSC)とは、電子楽器(特にシンセサイザー)やコンピュータなどの機器において音楽演奏データをネットワーク経由でリアルタイムに共有するための通信プロトコルである。
(引用: Wikipedia「OpenSound Control」

これで何ができるかって言うと、例えばバスドラムに合わせて、外部に信号を出してLEDを点灯させるみたいなことができます。つまりリアルタイムに変動する音楽に合わせて即応性の高い反応ができるわけですね!

そんなある日、私はあることを思いつきました。
虹色に発光する人
「OSCを使ってリアルタイムにポエトリーリーディングができるんじゃないか?」

これは失敗したコードの記事。

この失敗を見返したくない私が、

記事を書き上げるまで幾度となく絶望した。
暗虹色に発光する人

そんな、記事です。

1. とりあえずOSCを触る

まず公式ドキュメントを読みましょう。
基本的には公式ドキュメントの通りにしておけば、すべて動きます。
ちなみにTydal CyclesのOSCなので、間違ってもSuperColiderに打ち込んで実行しようとしないこと。私は1時間溶かしました。

let visualTarget = Target
      { oName = "processing"   -- ターゲットの名前
      , oAddress = "localhost" -- localhostに送信
      , oPort = 2020           -- Processingがリッスンしているポート番号
      , oLatency = 10000         -- レイテンシ調整
      , oSchedule = Pre MessageStamp      -- スケジューリング設定 おい!スペース空いてて良いんですね!?
      , oWindow = Nothing
      , oHandshake = False
      , oBusPort = Nothing }

let oscVisual = OSC "/visual" $ ArgList
      [ ("s", Nothing)
      , ("cycle", Just $ VF 0)
      , ("sec", Just $ VF 0)
      , ("usec", Just $ VF 0)
      ]

let oscmap = [(visualTarget, [oscVisual])]

stream <- startStream defaultConfig oscmap

streamReplace stream 1 $ s "testbb"

せっかくなので、それを受信するコードも書いてみましょう。とりあえずPythonで。

import argparse
from pythonosc import dispatcher
from pythonosc import osc_server

def parse_osc_message(message):
    parsed = {}
    for i in range(0, len(message), 2):  # 2個ずつ取り出す
        key = message[i]
        value = message[i + 1]
        parsed[key] = value
    return parsed

def handle_cycles(address, *args):    # Cycle表示用の関数を作るつもりだったけど、やっぱやめたのでこういう関数名です
    print(args)


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--ip",
                        default="127.0.0.1", help="The ip to listen on")
    parser.add_argument("--port",
                        type=int, default=2020, help="The port to listen on")
    args = parser.parse_args()

    dispatcher = dispatcher.Dispatcher()
    dispatcher.map("/*", handle_cycles)

    server = osc_server.ThreadingOSCUDPServer(
        (args.ip, args.port), dispatcher)
    print("Serving on {}".format(server.server_address))
    server.serve_forever()

これを実行すると
image.png
ちゃんと受信できていますね。

2. BPMに合わせてVOICEVOXを喋らせる(誤差①)

やってることはこのツールと同じです→VOICEVOXの読み上げをBPMと同期するツールについて by melonadeさん
てっきりOSSかと思ったらそうでもなかったので、いい感じに自作。
とりあえずコードを書いてみます

1時間後

コードができました。

「よっしゃ!さっそく実行や!」ということでテキトーな文章で実行…!

実行ログ。正常に終了してそう

…ワクワク
    ドキドキ…

結果:
音声波形
波形上で、ポエトリーとBPMに線を引いている。その線は微妙にズレている

バカズレてる!!!!!!!!!!!!!

…これが今回の記事のメインテーマである誤差の1つ目です。そしてそれぞれ誤差にどのように対処するかが重要になってきます。

今回の誤差はたまたま変動しない誤差なので、実際に誤差を計測し、その分音声を遅らせることで事なきを得ました。

実際のコードはこちら

これの原因はマジでよくわからん 先行無音・後方無音は0秒に設定してるのになんかズレるのよ なんで?

3. この2つを同時に再生してみる(誤差②)

BPMに合わせた音声が生成できました。あとはこれを同時に再生するだけですね!
ではさっそく試してみましょう。

Enter text: ダン、ダン、ダン、…

とりあえずCLIで入力を受け付け、その文章を歌詞とします。
これで完璧にイカしたポエトリーリーディングがリアルタイムに…!

…ワクワク
    ドキドキ…

結果:
image.png

バカズレてる!!!!!!!!!!!!!!!!!!!!!!!!

これが今回の記事のメインテーマである誤差の2つ目です。
さらに今回の誤差はただの誤差ではありません。それは音声波形を見るとわかります。

音声波形にBPMとポエトリーに

なんとこの誤差は変動します。つまり、先程のように計測して固定値でズラすという方法は通用しません。
困った…。

黒色に染まる人

「もう打つ手はない…」
絶望に打ちひしがれながら、ズレたポエトリーを聞くしかありません。

人生には諦めなければならない瞬間があります。

そんな時、

夕焼けのように紅潮する人

ある天啓が舞い降ります。

4. 天啓

TydalCyclesから2つの道筋が示されている。1つ目がSuperDirtを通って音を鳴らすルート。2つ目が先述のPythonコードとPyAudioを通って音を鳴らすルート。

現在の構成は上図のようです。
TydalCyclesは単体で音がなるわけではありません。SuperDirtと合わせて使うものであり、SuperDirtにOSCを送ることでSuperDirtが音を鳴らします。
そして私はTydalCyclesからPythonサーバーまでに誤差の変動が生じていると考えました。

先ほどの画像のうち、TydalCyclesからPythonコードへの矢印が太くなっている。

そしてこの誤差の変動を無くす方法を思いつきました。

間に別のサーバーを噛ましてあげれば、誤差が一定になるのでは…?

試してみる価値はあります。やってみましょう。

5. そして、敗北。(誤差③)

ということでやってみましょう。まずはSuperDirtのポート番号をテキトーにズラします。
SuperColider上でFileから「Open user support directory」を選択し、downloaded-quarks>SuperDirtとフォルダを開いていきます。そこにある57120がポート番号なので、57121に書き換えます。

%%% コード or 画像

次に、57120にlistenして、TydalCyclesからのOSCを転送するサーバーを立てます。なぜかPythonだと上手くいかなかったので、Node.jsで。

これで完璧~(早瀬ユウカ)です。

…ワクワク
    ドキドキ…

ついに夢にまで見たポエトリーリーディングのリアルタイム自動生成が日の目を見ます。

…ワクワク
    ドキドキ…

思えばここまで長かった…。

…ワクワク
    ドキドキ…

途中で4年前のフリーゲームにドハマリして狂ってたけど、ついに…

…ワクワク
    ドキドキ…

ついに、完成するんだ!!!!!!

結果:
音声波形。明確に2つの山がズレている。

ズレてるし、なんか不整脈みたいなビート!!!!!!!!!!!!!!!!!!

6. 敗因

そもそも誤差の変動の発生箇所を見誤っていました。

3章2枚目の画像と同じ。TydalCyclesからPythonコードへの矢印が太くなっている。

てっきり上図の箇所で誤差が変動している(いわゆるジッター)ものだと思っていましたが…

PyAudioが赤くなっている

音声を再生するときに生じる誤差が変動しているみたいなんですよね。
これはPyAudioの責任ではありません。(むしろPyAudioは他のライブラリと比べて低遅延)
データの伝達がある以上、どうしても仕方ないことだと思います。
ということで、私の夢は潰えました。

暗闇に染まる人

人生には諦めなければならない瞬間があります。

以上です。

参考文献

ちなみに今回のコードまとめのリポジトリあります
BPMに合わせて音声を生成するパートは上手く行ってるはずなんで…。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?