diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml index bf6cd1ee08d9..39500fe1d827 100644 --- a/doc/classes/AudioServer.xml +++ b/doc/classes/AudioServer.xml @@ -359,6 +359,25 @@ If [param active] is [code]false[/code], stops the input stream if it is running. + + + + + + + + + + Plays [param playback] on the [param bus] audio bus from beginning, or from given [param start_time] in seconds. + + + + + + + Stops the [AudioStreamPlayback]. + + @@ -432,5 +451,14 @@ Represents the size of the [enum PlaybackType] enum. + + The audio will be played only on the first channel. This is the default. + + + The audio will be played on all surround channels. + + + The audio will be played on the second channel, which is usually the center. + diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index dae089ea9f10..fe63720f1535 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -69,7 +69,7 @@ The maximum number of sounds this node can play at the same time. Calling [method play] after this value is reached will cut off the oldest sounds. - + The mix target channels. Has no effect when two speakers or less are detected (see [enum AudioServer.SpeakerMode]). @@ -105,13 +105,13 @@ - + The audio will be played only on the first channel. This is the default. - + The audio will be played on all surround channels. - + The audio will be played on the second channel, which is usually the center. diff --git a/misc/extension_api_validation/4.6-stable/GH-#117430.txt b/misc/extension_api_validation/4.6-stable/GH-#117430.txt new file mode 100644 index 000000000000..99ae85675f14 --- /dev/null +++ b/misc/extension_api_validation/4.6-stable/GH-#117430.txt @@ -0,0 +1,6 @@ +GH-117430 +--------- +Validate extension JSON: Error: Field 'classes/AudioStreamPlayer/methods/get_mix_target/return_value': type changed value in new API, from "enum::AudioStreamPlayer.MixTarget" to "enum::AudioServer.MixTarget". +Validate extension JSON: Error: Field 'classes/AudioStreamPlayer/methods/set_mix_target/arguments/0': type changed value in new API, from "enum::AudioStreamPlayer.MixTarget" to "enum::AudioServer.MixTarget". + +Enum moved to AudioServer. Compatibility methods registered. diff --git a/scene/audio/audio_stream_player.compat.inc b/scene/audio/audio_stream_player.compat.inc index e16cd1a49786..2c4ff5468be5 100644 --- a/scene/audio/audio_stream_player.compat.inc +++ b/scene/audio/audio_stream_player.compat.inc @@ -40,6 +40,13 @@ bool AudioStreamPlayer::_is_autoplay_enabled_bind_compat_86907() { void AudioStreamPlayer::_bind_compatibility_methods() { ClassDB::bind_compatibility_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer::_is_autoplay_enabled_bind_compat_86907); + + ClassDB::bind_compatibility_method(D_METHOD("set_mix_target", "target"), (void (AudioStreamPlayer::*)(MixTarget))&AudioStreamPlayer::set_mix_target); + ClassDB::bind_compatibility_method(D_METHOD("get_mix_target"), (MixTarget (AudioStreamPlayer::*)() const) & AudioStreamPlayer::get_mix_target); + + BIND_ENUM_CONSTANT(MIX_TARGET_STEREO); + BIND_ENUM_CONSTANT(MIX_TARGET_SURROUND); + BIND_ENUM_CONSTANT(MIX_TARGET_CENTER); } #endif // DISABLE_DEPRECATED diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 1eaa80718ec9..1148c5b3c9cc 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -160,11 +160,11 @@ bool AudioStreamPlayer::is_autoplay_enabled() const { return internal->autoplay; } -void AudioStreamPlayer::set_mix_target(MixTarget p_target) { +void AudioStreamPlayer::set_mix_target(AudioServer::MixTarget p_target) { mix_target = p_target; } -AudioStreamPlayer::MixTarget AudioStreamPlayer::get_mix_target() const { +AudioServer::MixTarget AudioStreamPlayer::get_mix_target() const { return mix_target; } @@ -181,40 +181,7 @@ bool AudioStreamPlayer::get_stream_paused() const { } Vector AudioStreamPlayer::_get_volume_vector() { - Vector volume_vector; - // We need at most four stereo pairs (for 7.1 systems). - volume_vector.resize(4); - - // Initialize the volume vector to zero. - for (AudioFrame &channel_volume_db : volume_vector) { - channel_volume_db = AudioFrame(0, 0); - } - - float volume_linear = Math::db_to_linear(internal->volume_db); - - // Set the volume vector up according to the speaker mode and mix target. - // TODO do we need to scale the volume down when we output to more channels? - if (AudioServer::get_singleton()->get_speaker_mode() == AudioServer::SPEAKER_MODE_STEREO) { - volume_vector.write[0] = AudioFrame(volume_linear, volume_linear); - } else { - switch (mix_target) { - case MIX_TARGET_STEREO: { - volume_vector.write[0] = AudioFrame(volume_linear, volume_linear); - } break; - case MIX_TARGET_SURROUND: { - // TODO Make sure this is right. - volume_vector.write[0] = AudioFrame(volume_linear, volume_linear); - volume_vector.write[1] = AudioFrame(volume_linear, /* LFE= */ 1.0f); - volume_vector.write[2] = AudioFrame(volume_linear, volume_linear); - volume_vector.write[3] = AudioFrame(volume_linear, volume_linear); - } break; - case MIX_TARGET_CENTER: { - // TODO Make sure this is right. - volume_vector.write[1] = AudioFrame(volume_linear, /* LFE= */ 1.0f); - } break; - } - } - return volume_vector; + return AudioServer::get_singleton()->create_volume_vector(internal->volume_db, mix_target); } void AudioStreamPlayer::_validate_property(PropertyInfo &p_property) const { @@ -293,10 +260,6 @@ void AudioStreamPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_type", PROPERTY_HINT_ENUM, "Default,Stream,Sample"), "set_playback_type", "get_playback_type"); ADD_SIGNAL(MethodInfo("finished")); - - BIND_ENUM_CONSTANT(MIX_TARGET_STEREO); - BIND_ENUM_CONSTANT(MIX_TARGET_SURROUND); - BIND_ENUM_CONSTANT(MIX_TARGET_CENTER); } AudioStreamPlayer::AudioStreamPlayer() { diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h index abaed688d1e4..a6c49a359081 100644 --- a/scene/audio/audio_stream_player.h +++ b/scene/audio/audio_stream_player.h @@ -42,16 +42,18 @@ class AudioStreamPlayer : public Node { GDCLASS(AudioStreamPlayer, Node); public: +#ifndef DISABLE_DEPRECATED enum MixTarget { MIX_TARGET_STEREO, MIX_TARGET_SURROUND, MIX_TARGET_CENTER }; +#endif // DISABLE_DEPRECATED private: AudioStreamPlayerInternal *internal = nullptr; - MixTarget mix_target = MIX_TARGET_STEREO; + AudioServer::MixTarget mix_target = AudioServer::MIX_TARGET_STEREO; void _set_playing(bool p_enable); bool _is_active() const; @@ -100,8 +102,8 @@ class AudioStreamPlayer : public Node { void set_autoplay(bool p_enable); bool is_autoplay_enabled() const; - void set_mix_target(MixTarget p_target); - MixTarget get_mix_target() const; + void set_mix_target(AudioServer::MixTarget p_target); + AudioServer::MixTarget get_mix_target() const; void set_stream_paused(bool p_pause); bool get_stream_paused() const; @@ -116,4 +118,6 @@ class AudioStreamPlayer : public Node { ~AudioStreamPlayer(); }; +#ifndef DISABLE_DEPRECATED VARIANT_ENUM_CAST(AudioStreamPlayer::MixTarget) +#endif // DISABLE_DEPRECATED diff --git a/servers/audio/audio_server.cpp b/servers/audio/audio_server.cpp index 98bb2cebd942..893a97b059fe 100644 --- a/servers/audio/audio_server.cpp +++ b/servers/audio/audio_server.cpp @@ -1319,6 +1319,61 @@ void AudioServer::stop_playback_stream(Ref p_playback) { } while (!playback_node->state.compare_exchange_strong(old_state, new_state)); } +Vector AudioServer::create_volume_vector(float p_volume_db, MixTarget p_mix_target) const { + Vector volume_vector; + // We need at most four stereo pairs (for 7.1 systems). + volume_vector.resize(4); + + // Initialize the volume vector to zero. + for (AudioFrame &channel_volume_db : volume_vector) { + channel_volume_db = AudioFrame(0, 0); + } + + float volume_linear = Math::db_to_linear(p_volume_db); + + // Set the volume vector up according to the speaker mode and mix target. + // TODO do we need to scale the volume down when we output to more channels? + if (get_speaker_mode() == AudioServer::SPEAKER_MODE_STEREO) { + volume_vector.write[0] = AudioFrame(volume_linear, volume_linear); + } else { + switch (p_mix_target) { + case MIX_TARGET_STEREO: { + volume_vector.write[0] = AudioFrame(volume_linear, volume_linear); + } break; + case MIX_TARGET_SURROUND: { + // TODO Make sure this is right. + volume_vector.write[0] = AudioFrame(volume_linear, volume_linear); + volume_vector.write[1] = AudioFrame(volume_linear, /* LFE= */ 1.0f); + volume_vector.write[2] = AudioFrame(volume_linear, volume_linear); + volume_vector.write[3] = AudioFrame(volume_linear, volume_linear); + } break; + case MIX_TARGET_CENTER: { + // TODO Make sure this is right. + volume_vector.write[1] = AudioFrame(volume_linear, /* LFE= */ 1.0f); + } break; + } + } + + return volume_vector; +} + +void AudioServer::_start_playback_stream(Ref p_playback, const StringName &p_bus, float p_volume_db_offset, MixTarget p_mix_target, float p_start_time, float p_pitch_scale) { + ERR_FAIL_COND(p_playback.is_null()); + + Vector volume_vector = create_volume_vector(p_volume_db_offset, p_mix_target); + start_playback_stream(p_playback, p_bus, volume_vector, p_start_time, p_pitch_scale); + + // Sample handling. + if (p_playback->get_is_sample() && p_playback->get_sample_playback().is_valid()) { + Ref sample_playback = p_playback->get_sample_playback(); + sample_playback->offset = p_start_time; + sample_playback->bus = p_bus; + sample_playback->volume_vector = volume_vector; + sample_playback->pitch_scale = p_pitch_scale; + start_sample_playback(sample_playback); + } +} + void AudioServer::set_playback_bus_exclusive(Ref p_playback, const StringName &p_bus, Vector p_volumes) { ERR_FAIL_COND(p_volumes.size() != MAX_CHANNELS_PER_BUS); @@ -2113,6 +2168,9 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("is_stream_registered_as_sample", "stream"), &AudioServer::is_stream_registered_as_sample); ClassDB::bind_method(D_METHOD("register_stream_as_sample", "stream"), &AudioServer::register_stream_as_sample); + ClassDB::bind_method(D_METHOD("start_playback_stream", "playback", "bus", "volume_db_offset", "mix_target", "start_time", "pitch_scale"), &AudioServer::_start_playback_stream, DEFVAL(0), DEFVAL(MIX_TARGET_STEREO), DEFVAL(0), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("stop_playback_stream", "playback"), &AudioServer::stop_playback_stream); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bus_count"), "set_bus_count", "get_bus_count"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "output_device"), "set_output_device", "get_output_device"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "input_device"), "set_input_device", "get_input_device"); @@ -2133,6 +2191,10 @@ void AudioServer::_bind_methods() { BIND_ENUM_CONSTANT(PLAYBACK_TYPE_STREAM); BIND_ENUM_CONSTANT(PLAYBACK_TYPE_SAMPLE); BIND_ENUM_CONSTANT(PLAYBACK_TYPE_MAX); + + BIND_ENUM_CONSTANT(MIX_TARGET_STEREO); + BIND_ENUM_CONSTANT(MIX_TARGET_SURROUND); + BIND_ENUM_CONSTANT(MIX_TARGET_CENTER); } AudioServer::AudioServer() { diff --git a/servers/audio/audio_server.h b/servers/audio/audio_server.h index 104b162f2806..e89aeddd6c7f 100644 --- a/servers/audio/audio_server.h +++ b/servers/audio/audio_server.h @@ -196,6 +196,12 @@ class AudioServer : public Object { PLAYBACK_TYPE_MAX }; + enum MixTarget { + MIX_TARGET_STEREO, + MIX_TARGET_SURROUND, + MIX_TARGET_CENTER + }; + enum { AUDIO_DATA_INVALID_ID = -1, MAX_CHANNELS_PER_BUS = 4, @@ -436,6 +442,9 @@ class AudioServer : public Object { void start_playback_stream(Ref p_playback, const HashMap> &p_bus_volumes, float p_start_time = 0, float p_pitch_scale = 1, float p_highshelf_gain = 0, float p_attenuation_cutoff_hz = 0); void stop_playback_stream(Ref p_playback); + Vector create_volume_vector(float p_volume_db, MixTarget p_mix_target) const; + void _start_playback_stream(Ref p_playback, const StringName &p_bus, float p_volume_db_offset = 0, MixTarget p_mix_target = MIX_TARGET_STEREO, float p_start_time = 0, float p_pitch_scale = 1); + void set_playback_bus_exclusive(Ref p_playback, const StringName &p_bus, Vector p_volumes); void set_playback_bus_volumes_linear(Ref p_playback, const HashMap> &p_bus_volumes); void set_playback_all_bus_volumes_linear(Ref p_playback, Vector p_volumes); @@ -526,6 +535,7 @@ class AudioServer : public Object { VARIANT_ENUM_CAST(AudioServer::SpeakerMode) VARIANT_ENUM_CAST(AudioServer::PlaybackType) +VARIANT_ENUM_CAST(AudioServer::MixTarget) class AudioBusLayout : public Resource { GDCLASS(AudioBusLayout, Resource);