波形からサウンドを生成する AudioStreamGeneratorというのを使って、簡単な波形を生成するプログラムを書いてみました。
ソースコード
作成方法
作成方法は「AudioStreamGeneratorリソースを作る」「AudioStreamPlayer」にそれを読み込ませる、という手順です。 まずはファイルシステムを右クリックして「+新規作成 > リソース」を選びます。

そして "AudioStreamGenerator" を作成します。
あとはこれを AudioStreamPlayer[2D/3D]に読み込ませるだけですね。

サンプルコード
サンプルとして以下のコードを書いてみました。
extends Node2D # 波形タイプ enum eWave { Sine, Triangle, Square, Saw, WhiteNoise, } const SEMITONE = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"] @onready var player: AudioStreamPlayer2D = $AudioStreamPlayer2D # ゲイン @onready var slider_gain = $HSliderGain # 再生時間 @onready var slider_time = $HSliderTime # 波形. @onready var list_oscillator = $OscillatorList # オクターブ @onready var list_octave = $OctaveList # 半音階 @onready var list_semitone = $SemitoneList # ビットレート. @export var mix_rate_fallback: int = 44100 var _gen: AudioStreamGenerator var _pb: AudioStreamGeneratorPlayback var _phase: float = 0.0 var _rand := RandomNumberGenerator.new() var _gain: float = 0.0 func _ready() -> void: _gen = player.stream as AudioStreamGenerator assert(_gen != null) for k in eWave.keys(): list_oscillator.add_item(k) for v in SEMITONE: list_semitone.add_item(v) for i in range(1, 7): list_octave.add_item("%d"%i) list_oscillator.select(3) # Saw list_semitone.select(9) # A list_octave.select(3) # 4 # 再生実行. func _on_button_play_pressed() -> void: # 音量取得 _gain = slider_gain.value if _gen.mix_rate <= 0: _gen.mix_rate = mix_rate_fallback # 音の長さ. var buffer_len_sec = slider_time.value _gen.buffer_length = buffer_len_sec # 再生開始(この時点で出音したくないなら一時停止にする) player.play() player.stream_paused = true # ← 4.x ならこれでサイレント再生にできる _pb = player.get_stream_playback() as AudioStreamGeneratorPlayback assert(_pb != null) # 「空き容量」ぶんだけ一気に生成して詰める var mix_rate: int = int(_gen.mix_rate) var frames_to_fill: int = _pb.get_frames_available() var octave = list_octave.selected + 1 # 1始まりなので+1 var note = list_semitone.selected var semitone = note + (octave - 4) * 12 # A4 = 440Hz を基準に計算 var freq_hz = 440.0 * pow(2.0, (semitone - 9) / 12.0) var step: float = TAU * freq_hz / float(mix_rate) for i in range(frames_to_fill): var s: float = _sample_at_phase(_phase) * _gain _phase += step if _phase >= TAU: _phase -= TAU _pb.push_frame(Vector2(s, s)) # 先詰めが終わったら、必要なタイミングで再生を解除 player.stream_paused = false # 指定フェーズでの波形サンプルを返す func _sample_at_phase(ph: float) -> float: match list_oscillator.selected: eWave.Sine: return sin(ph) eWave.Triangle: # -1..1 の三角波: 2/pi * asin(sin(theta)) return (2.0 / PI) * asin(sin(ph)) eWave.Square: # 矩形波: sinが0以上なら1、未満なら-1 return 1.0 if sin(ph) >= 0.0 else -1.0 eWave.Saw: # ノコギリ波: -1..1 return (fmod(ph / TAU, 1.0) * 2.0) - 1.0 eWave.WhiteNoise: # ホワイトノイズ: -1..1 の乱数 return _rand.randf_range(-1.0, 1.0) _: return 0.0
機能としては以下ものがあります。
- 波形の選択 (Sin, Triangle, Square, Saw, WhiteNoise)
- 音程 (C〜B, 1〜6)
- 音量
- 再生時間

