Skip to content

Commit

Permalink
[AudioStreamGenerator] Add mixing rate presets, update docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
bruvzg committed Feb 11, 2025
1 parent 296de7d commit 3965bdf
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 11 deletions.
19 changes: 19 additions & 0 deletions doc/classes/AudioStreamGenerator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,25 @@
The sample rate to use (in Hz). Higher values are more demanding for the CPU to generate, but result in better quality.
In games, common sample rates in use are [code]11025[/code], [code]16000[/code], [code]22050[/code], [code]32000[/code], [code]44100[/code], and [code]48000[/code].
According to the [url=https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem]Nyquist-Shannon sampling theorem[/url], there is no quality difference to human hearing when going past 40,000 Hz (since most humans can only hear up to ~20,000 Hz, often less). If you are generating lower-pitched sounds such as voices, lower sample rates such as [code]32000[/code] or [code]22050[/code] may be usable with no loss in quality.
[b]Note:[/b] [AudioStreamGenerator] is not automatically resampling input data, to produce expected result [member mix_rate_mode] should match the sampling rate of input data.
[b]Note:[/b] If you are using [AudioEffectCapture] as the source of your data, set [member mix_rate_mode] to [constant MIX_RATE_INPUT] or [constant MIX_RATE_OUTPUT] to automatically match current [AudioServer] mixing rate.
</member>
<member name="mix_rate_mode" type="int" setter="set_mix_rate_mode" getter="get_mix_rate_mode" enum="AudioStreamGenerator.AudioStreamGeneratorMixRate" default="2">
Mixing rate mode. If set to [constant MIX_RATE_CUSTOM], [member mix_rate] is used, otherwise current [AudioServer] mixing rate is used.
</member>
</members>
<constants>
<constant name="MIX_RATE_OUTPUT" value="0" enum="AudioStreamGeneratorMixRate">
Current [AudioServer] output mixing rate.
</constant>
<constant name="MIX_RATE_INPUT" value="1" enum="AudioStreamGeneratorMixRate">
Current [AudioServer] input mixing rate.
</constant>
<constant name="MIX_RATE_CUSTOM" value="2" enum="AudioStreamGeneratorMixRate">
Custom mixing rate, specified by [member mix_rate].
</constant>
<constant name="MIX_RATE_MAX" value="3" enum="AudioStreamGeneratorMixRate">
Maximum value for the mixing rate mode enum.
</constant>
</constants>
</class>
4 changes: 3 additions & 1 deletion doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,9 @@
[b]Note:[/b] If the operating system blocks access to audio input devices (due to the user's privacy settings), audio capture will only return silence. On Windows 10 and later, make sure that apps are allowed to access the microphone in the OS' privacy settings.
</member>
<member name="audio/driver/mix_rate" type="int" setter="" getter="" default="44100">
The mixing rate used for audio (in Hz). In general, it's better to not touch this and leave it to the host operating system.
Target mixing rate used for audio (in Hz). In general, it's better to not touch this and leave it to the host operating system.
[b]Note:[/b] On iOS and macOS, mixing rate is determined by audio driver, this value is ignored.
[b]Note:[/b] Input and output mixing rates might be different. Use [method AudioServer.get_mix_rate] and [method AudioServer.get_input_mix_rate] to get actual values.
</member>
<member name="audio/driver/mix_rate.web" type="int" setter="" getter="" default="0">
Safer override for [member audio/driver/mix_rate] in the Web platform. Here [code]0[/code] means "let the browser choose" (since some browsers do not like forcing the mix rate).
Expand Down
38 changes: 31 additions & 7 deletions servers/audio/effects/audio_stream_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ float AudioStreamGenerator::get_mix_rate() const {
return mix_rate;
}

void AudioStreamGenerator::set_mix_rate_mode(AudioStreamGenerator::AudioStreamGeneratorMixRate p_mix_rate_mode) {
ERR_FAIL_INDEX(p_mix_rate_mode, AudioStreamGeneratorMixRate::MIX_RATE_MAX);
mix_rate_mode = p_mix_rate_mode;
}

AudioStreamGenerator::AudioStreamGeneratorMixRate AudioStreamGenerator::get_mix_rate_mode() const {
return mix_rate_mode;
}

void AudioStreamGenerator::set_buffer_length(float p_seconds) {
buffer_len = p_seconds;
}
Expand All @@ -46,11 +55,22 @@ float AudioStreamGenerator::get_buffer_length() const {
return buffer_len;
}

float AudioStreamGenerator::_get_target_rate() const {
switch (mix_rate_mode) {
case AudioStreamGeneratorMixRate::MIX_RATE_OUTPUT:
return AudioServer::get_singleton()->get_mix_rate();
case AudioStreamGeneratorMixRate::MIX_RATE_INPUT:
return AudioServer::get_singleton()->get_input_mix_rate();
default:
return mix_rate;
}
}

Ref<AudioStreamPlayback> AudioStreamGenerator::instantiate_playback() {
Ref<AudioStreamGeneratorPlayback> playback;
playback.instantiate();
playback->generator = this;
int target_buffer_size = mix_rate * buffer_len;
int target_buffer_size = _get_target_rate() * buffer_len;
playback->buffer.resize(nearest_shift(target_buffer_size));
playback->buffer.clear();
return playback;
Expand All @@ -72,16 +92,20 @@ void AudioStreamGenerator::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mix_rate", "hz"), &AudioStreamGenerator::set_mix_rate);
ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamGenerator::get_mix_rate);

ClassDB::bind_method(D_METHOD("set_mix_rate_mode", "mode"), &AudioStreamGenerator::set_mix_rate_mode);
ClassDB::bind_method(D_METHOD("get_mix_rate_mode"), &AudioStreamGenerator::get_mix_rate_mode);

ClassDB::bind_method(D_METHOD("set_buffer_length", "seconds"), &AudioStreamGenerator::set_buffer_length);
ClassDB::bind_method(D_METHOD("get_buffer_length"), &AudioStreamGenerator::get_buffer_length);

ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_rate_mode", PROPERTY_HINT_ENUM, "System Output Rate,System Input Rate,Custom Rate"), "set_mix_rate_mode", "get_mix_rate_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mix_rate", PROPERTY_HINT_RANGE, "20,192000,1,suffix:Hz"), "set_mix_rate", "get_mix_rate");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "buffer_length", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), "set_buffer_length", "get_buffer_length");
}

AudioStreamGenerator::AudioStreamGenerator() {
mix_rate = 44100;
buffer_len = 0.5;
BIND_ENUM_CONSTANT(MIX_RATE_OUTPUT);
BIND_ENUM_CONSTANT(MIX_RATE_INPUT);
BIND_ENUM_CONSTANT(MIX_RATE_CUSTOM);
BIND_ENUM_CONSTANT(MIX_RATE_MAX);
}

////////////////
Expand Down Expand Up @@ -162,12 +186,12 @@ int AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_fram
skips++;
}

mixed += p_frames / generator->get_mix_rate();
mixed += p_frames / generator->_get_target_rate();
return p_frames;
}

float AudioStreamGeneratorPlayback::get_stream_sampling_rate() {
return generator->get_mix_rate();
return generator->_get_target_rate();
}

void AudioStreamGeneratorPlayback::start(double p_from_pos) {
Expand Down
23 changes: 20 additions & 3 deletions servers/audio/effects/audio_stream_generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,31 @@
class AudioStreamGenerator : public AudioStream {
GDCLASS(AudioStreamGenerator, AudioStream);

float mix_rate;
float buffer_len;
public:
enum AudioStreamGeneratorMixRate {
MIX_RATE_OUTPUT,
MIX_RATE_INPUT,
MIX_RATE_CUSTOM,
MIX_RATE_MAX,
};

private:
AudioStreamGeneratorMixRate mix_rate_mode = MIX_RATE_CUSTOM;
float mix_rate = 44100;
float buffer_len = 0.5;

protected:
static void _bind_methods();

public:
float _get_target_rate() const;

void set_mix_rate(float p_mix_rate);
float get_mix_rate() const;

void set_mix_rate_mode(AudioStreamGeneratorMixRate p_mix_rate_mode);
AudioStreamGeneratorMixRate get_mix_rate_mode() const;

void set_buffer_length(float p_seconds);
float get_buffer_length() const;

Expand All @@ -55,7 +70,7 @@ class AudioStreamGenerator : public AudioStream {

virtual double get_length() const override;
virtual bool is_monophonic() const override;
AudioStreamGenerator();
AudioStreamGenerator() {}
};

class AudioStreamGeneratorPlayback : public AudioStreamPlaybackResampled {
Expand Down Expand Up @@ -96,4 +111,6 @@ class AudioStreamGeneratorPlayback : public AudioStreamPlaybackResampled {
AudioStreamGeneratorPlayback();
};

VARIANT_ENUM_CAST(AudioStreamGenerator::AudioStreamGeneratorMixRate);

#endif // AUDIO_STREAM_GENERATOR_H

0 comments on commit 3965bdf

Please sign in to comment.