So I’m trying to create audio in real time. I looked into the audio system and audioStreamGenerator seems like utter nonsense. The audioStreamGeneratorPlayback is gaurded like a vault and tries to force you to fill the generated buffer on the audioStreamPlayer itself. I don’t want to do that. so I came up with this.
@tool
extends AudioStream
class_name clap_sound
var my_playback: AudioStreamGeneratorPlayback
var sample_hz: float = 44100
var pulse_hz = 440.0
var phase = 0.0
func _make_stream():
var new_player: AudioStreamPlayer = AudioStreamPlayer.new()
new_player.stream = AudioStreamGenerator.new()
GlobalControlsCarrier.get_tree().root.add_child(new_player)
new_player.play()
my_playback = new_player.get_stream_playback()
new_player.queue_free()
func _instantiate_playback() -> AudioStreamPlayback:
_make_stream()
var increment = pulse_hz / sample_hz
var frames_available = my_playback.get_frames_available()
for i in range(frames_available):
my_playback.push_frame(Vector2.ONE * sin(phase * TAU))
phase = fmod(phase + increment, 1.0)
return my_playback
But it seems sloppy and cumbersome that I must hijack audioStreamPlayer to create an audioStreamGenerator playback. and on top of that AudioStreamGenerator’s .instantiate_playback() is NEVER called. It seems very strange to me so I figure I am missing something. is there a better way to do this?
Your code makes little sense. What are you trying to do? If you only want to generate a sound once and use it multiple times you can write an EditorScript that generates a wav file for example that you could use later.
If you want to do it at runtime you have two options. Generate the sound once with a AudioStreamWAV or generate it procedurally with an AudioStreamGenerator
You can check this demo on how to use a AudioStreamGenerator:
Note that gdscript is not really suited for real-time audio generation. It may work for simple sounds but it will struggle for more complex sounds.
If what you are after is to create your own AudioStream you have to implement it in C++ using GDExtension as it’s not possible to use gdscript or C# for that and you’ll need to implement both an AudioStream and its AudioStreamPlayback which is the actual object where mixing with the audio buffer happens.
My problem is specifically that I want to generate the audio when called, without reliance on the AudioStreamPlayer node. Both the demo project you linked, and the documentation, all show an example in which AudioStreamPlayer is used along with AudioStreamGenerator to create the audio. Specifically, both examples call AudioStreamPlayer.play() then AudioStreamPlayer.get_stream_playback().
From documentation - “In the example above, the “AudioStreamPlayer” node must use an AudioStreamGenerator as its stream. The fill_buffer function provides audio data for approximating a sine wave.”
I don’t want to do this, I want to generate the audio within the resource itself. To achieve this I have no problem with using GDextension, But I would like to know if it is even possible to generate this audio using audioStreamGenerator independent of the audioStreamPlayer node’s assistance.
My problem is specifically that I want to generate the audio when called, without reliance on the AudioStreamPlayer node
You need an AudioStreamPlayer to play the audio. It’s not possible to play audio without one.
if you want to use an AudioStreamGenerator you need to access its AudioStreamGeneratorPlayback object to fill its buffer. It’s useless to get it from the AudioStream.instantiate_playback() as its purpose is for extending other AudioStreams and can’t be played directly. Also, AudioStreamGeneratorPlayback uses a ring buffer internally so you wouldn’t be able to fill much of it until you consume it with AudioStreamPlayback.mix_audio() which, again, you won’t be able to play unless you pump it back to another AudioStreamPlayback object coming from an AudioStreamPlayer.
If you want to create your own AudioStream using GDExtension go ahead. But that AudioStream will need to be used by an AudioStreamPlayer at some point.
I am aware that AudioStreamPlayer is needed to play audio. what I am getting at in my post is that Playing the specific audio is locked to the specific AudioStreamPlayer , as that is where the script to modify the buffer lies. I am trying to make an AudioStream resource that holds information for procedurally generated audio and can play on any AudioStreamPlayer or be placed inside AudioStreamRandomizer without a script on the AudioStreamPlayer. That being said, Could you point me towards some resources for extending and using AudioStream? if that is the best option.