Open4

GodotEngineのオーディオ出力の補間について

MachiaWorksMachiaWorks

GodotEngineで少しシンセサイザーを作っていたんだけど、
なんかオーディオ周りで補間が発生している可能性が高いのでメモっておく。

これは何かというと「波形メモリ音源っぽい波形をレンダリングして出力した結果」。
以下のコードで書き込み。

コード

func osc_wave_mem( phase):
	var out = 0.0;
	var mem_size = 16.0
	for i in range(1,mem_size+1):
		if phase < i/mem_size:
			out = sin( (i-1)/mem_size*TAU)
			# 終了
			break;
	return out

他のレンダリング関連のコードは省略。

何が起きてるか

今回のコードは「周期を16分割して、各範囲内では一定の値になるように出力する」形。
つまり、完全なサイン波としては出力されない形になる。

にも関わらず、画像のようになだらかに波形が変化した状態で出力されている。
また、上記にて記載した「一定の値」として出力されていない。

よって、GodotEngine内で補間が行われた上で出力されているものと考える。
(ちなみにWin32APIとかで出力すると補間全然しない場合変化差分が急激なレベルのオーディオが出力されます)

怪しそうな箇所

https://github.com/godotengine/godot/blob/master/servers/audio_server.cpp

https://github.com/godotengine/godot/blob/master/servers/audio/audio_stream.cpp

影響

単なる出力だけであれば、問題ない。アプリのクセとして定義可能。
また、ソフトウェアで波形を生成する場合、IOの値が強烈に変更される可能性が高く、
スピーカーに影響を与える可能性も大きい。
それを軽減する意味では機能が存在するのはありがたい。

ただ、オーディオのオフラインレンダリングを考慮する場合、
素直にファイル書き出しを行うだけでは、上記補間を考慮しないで出力されることになる。

言ってしまうと、「再生内容とオフラインレンダリング内容に差異が発生する」ことになる。

現在考えられる対応策は以下。

  • 補間コードをオフラインレンダリング処理に移植
  • オーディオのアウトプットを録音できないか検討(その場合オンラインレンダリング扱いになる)
  • 独自の補完処理を実装(その場合差異が発生することを許容する必要あり)
MachiaWorksMachiaWorks

情報ありがとうございます。

プロジェクトは48kで組んでみましたが、補間状況は変わらない様子。
(それどころかうちの環境だと44.1k固定。他の環境だと録音が困難orz)

とりあえず件のissueにあったプロジェクトの実装を参考にすると
mix_rateは取得できそうなので、それ使ってスピード調整するとかかなあ・・・。

MachiaWorksMachiaWorks

1年前のスクラップへの追記になるけど、情報の記載があった箇所を見つけました。
https://docs.godotengine.org/ja/stable/development/cpp/custom_audiostreams.html

これ見ると、GodotEngineはそもそも3次補間を提供しているということで、このサンプルソースを参考に補間処理を食わせないようにできれば回避できるのでは、と思いました。
(具体的にはAudioStreamPlaybackResampledクラスを継承しない形で実装していくとかかなあ・・・その前に他クラスが現状扱えるか見たほうが早いかもしれない)