Custom AudioStreams


AudioStream is the base class of all audio emitting objects. AudioStreamPlayer binds onto an AudioStream to emit PCM data into an AudioServer which manages audio drivers.

All audio resources require two audio based classes: AudioStream and AudioStreamPlayback. As a data container, AudioStream contains the resource and exposes itself to GDScript. AudioStream references its own internal custom AudioStreamPlayback which translates AudioStream into PCM data.

This guide assumes the reader knows how to create C++ modules. If not, refer to this guide Custom modules in C++.


What for?

  • Binding external libraries (like Wwise, FMOD, etc).

  • Adding custom audio queues

  • Adding support for more audio formats

Create an AudioStream

An AudioStream consists of three components: data container, stream name, and an AudioStreamPlayback friend class generator. Audio data can be loaded in a number of ways such as with an internal counter for a tone generator, internal/external buffer, or a file reference.

Some AudioStreams need to be stateless such as objects loaded from ResourceLoader. ResourceLoader loads once and references the same object regardless how many times load is called on a specific resource. Therefore, playback state must be self-contained in AudioStreamPlayback.

/* audiostream_mytone.h */

#include "core/reference.h"
#include "core/resource.h"
#include "servers/audio/audio_stream.h"

class AudioStreamMyTone : public AudioStream {
        GDCLASS(AudioStreamMyTone, AudioStream)

        friend class AudioStreamPlaybackMyTone;
        uint64_t pos;
        int mix_rate;
        bool stereo;
        int hz;

        void reset();
        void set_position(uint64_t pos);
        virtual Ref<AudioStreamPlayback> instance_playback();
        virtual String get_stream_name() const;
        void gen_tone(int16_t *pcm_buf, int size);
        virtual float get_length() const { return 0; } // if supported, otherwise return 0

        static void _bind_methods();
/* audiostream_mytone.cpp */

#include "audiostream_mytone.h"

                : mix_rate(44100), stereo(false), hz(639) {

Ref<AudioStreamPlayback> AudioStreamMyTone::instance_playback() {
        Ref<AudioStreamPlaybackMyTone> talking_tree;
        talking_tree->base = Ref<AudioStreamMyTone>(this);
        return talking_tree;

String AudioStreamMyTone::get_stream_name() const {
        return "MyTone";
void AudioStreamMyTone::reset() {
void AudioStreamMyTone::set_position(uint64_t p) {
        pos = p;
void AudioStreamMyTone::gen_tone(int16_t *pcm_buf, int size) {
        for (int i = 0; i < size; i++) {
                pcm_buf[i] = 32767.0 * sin(2.0 * Math_PI * double(pos + i) / (double(mix_rate) / double(hz)));
        pos += size;
void AudioStreamMyTone::_bind_methods() {
        ClassDB::bind_method(D_METHOD("reset"), &AudioStreamMyTone::reset);
        ClassDB::bind_method(D_METHOD("get_stream_name"), &AudioStreamMyTone::get_stream_name);


Create an AudioStreamPlayback

AudioStreamPlayer uses mix callback to obtain PCM data. The callback must match sample rate and fill the buffer.

Since AudioStreamPlayback is controlled by the audio thread, i/o and dynamic memory allocation are forbidden.

/*  audiostreamplayer_mytone.h */

#include "core/reference.h"
#include "core/resource.h"
#include "servers/audio/audio_stream.h"