diff options
-rw-r--r-- | doc/classes/AudioStream.xml | 13 | ||||
-rw-r--r-- | doc/classes/AudioStreamPlayback.xml | 15 | ||||
-rw-r--r-- | modules/minimp3/audio_stream_mp3.cpp | 29 | ||||
-rw-r--r-- | modules/minimp3/audio_stream_mp3.h | 7 | ||||
-rw-r--r-- | modules/vorbis/audio_stream_ogg_vorbis.cpp | 32 | ||||
-rw-r--r-- | modules/vorbis/audio_stream_ogg_vorbis.h | 7 | ||||
-rw-r--r-- | scene/2d/audio_stream_player_2d.cpp | 69 | ||||
-rw-r--r-- | scene/2d/audio_stream_player_2d.h | 12 | ||||
-rw-r--r-- | scene/3d/audio_stream_player_3d.cpp | 68 | ||||
-rw-r--r-- | scene/3d/audio_stream_player_3d.h | 12 | ||||
-rw-r--r-- | scene/audio/audio_stream_player.cpp | 68 | ||||
-rw-r--r-- | scene/audio/audio_stream_player.h | 12 | ||||
-rw-r--r-- | servers/audio/audio_stream.cpp | 25 | ||||
-rw-r--r-- | servers/audio/audio_stream.h | 19 |
14 files changed, 382 insertions, 6 deletions
diff --git a/doc/classes/AudioStream.xml b/doc/classes/AudioStream.xml index 12e09b235f..6e30775fee 100644 --- a/doc/classes/AudioStream.xml +++ b/doc/classes/AudioStream.xml @@ -28,6 +28,12 @@ <description> </description> </method> + <method name="_get_parameter_list" qualifiers="virtual const"> + <return type="Dictionary[]" /> + <description> + Return the controllable parameters of this stream. This array contains dictionaries with a property info description format (see [method Object.get_property_list]). Additionally, the default value for this parameter must be added tho each dictionary in "default_value" field. + </description> + </method> <method name="_get_stream_name" qualifiers="virtual const"> <return type="String" /> <description> @@ -62,4 +68,11 @@ </description> </method> </methods> + <signals> + <signal name="parameter_list_changed"> + <description> + Signal to be emitted to notify when the parameter list changed. + </description> + </signal> + </signals> </class> diff --git a/doc/classes/AudioStreamPlayback.xml b/doc/classes/AudioStreamPlayback.xml index 7692690b5e..a090989194 100644 --- a/doc/classes/AudioStreamPlayback.xml +++ b/doc/classes/AudioStreamPlayback.xml @@ -15,6 +15,13 @@ <description> </description> </method> + <method name="_get_parameter" qualifiers="virtual const"> + <return type="Variant" /> + <param index="0" name="name" type="StringName" /> + <description> + Return the current value of a playback parameter by name (see [method AudioStream._get_parameter_list]). + </description> + </method> <method name="_get_playback_position" qualifiers="virtual const"> <return type="float" /> <description> @@ -39,6 +46,14 @@ <description> </description> </method> + <method name="_set_parameter" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="name" type="StringName" /> + <param index="1" name="value" type="Variant" /> + <description> + Set the current value of a playback parameter by name (see [method AudioStream._get_parameter_list]). + </description> + </method> <method name="_start" qualifiers="virtual"> <return type="void" /> <param index="0" name="from_pos" type="float" /> diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp index 4efa4d329e..a46a1c93b5 100644 --- a/modules/minimp3/audio_stream_mp3.cpp +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -46,7 +46,9 @@ int AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) { int frames_mixed_this_step = p_frames; int beat_length_frames = -1; - bool beat_loop = mp3_stream->has_loop() && mp3_stream->get_bpm() > 0 && mp3_stream->get_beat_count() > 0; + bool use_loop = looping_override ? looping : mp3_stream->loop; + + bool beat_loop = use_loop && mp3_stream->get_bpm() > 0 && mp3_stream->get_beat_count() > 0; if (beat_loop) { beat_length_frames = mp3_stream->get_beat_count() * mp3_stream->sample_rate * 60 / mp3_stream->get_bpm(); } @@ -82,7 +84,7 @@ int AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) { else { //EOF - if (mp3_stream->loop) { + if (use_loop) { seek(mp3_stream->loop_offset); loops++; } else { @@ -143,6 +145,25 @@ void AudioStreamPlaybackMP3::tag_used_streams() { mp3_stream->tag_used(get_playback_position()); } +void AudioStreamPlaybackMP3::set_parameter(const StringName &p_name, const Variant &p_value) { + if (p_name == SNAME("looping")) { + if (p_value == Variant()) { + looping_override = false; + looping = false; + } else { + looping_override = true; + looping = p_value; + } + } +} + +Variant AudioStreamPlaybackMP3::get_parameter(const StringName &p_name) const { + if (looping_override && p_name == SNAME("looping")) { + return looping; + } + return Variant(); +} + AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() { if (mp3d) { mp3dec_ex_close(mp3d); @@ -232,6 +253,10 @@ bool AudioStreamMP3::is_monophonic() const { return false; } +void AudioStreamMP3::get_parameter_list(List<Parameter> *r_parameters) { + r_parameters->push_back(Parameter(PropertyInfo(Variant::BOOL, "looping", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE), Variant())); +} + void AudioStreamMP3::set_bpm(double p_bpm) { ERR_FAIL_COND(p_bpm < 0); bpm = p_bpm; diff --git a/modules/minimp3/audio_stream_mp3.h b/modules/minimp3/audio_stream_mp3.h index 30760703e3..7d85e0a321 100644 --- a/modules/minimp3/audio_stream_mp3.h +++ b/modules/minimp3/audio_stream_mp3.h @@ -47,6 +47,8 @@ class AudioStreamPlaybackMP3 : public AudioStreamPlaybackResampled { AudioFrame loop_fade[FADE_SIZE]; int loop_fade_remaining = FADE_SIZE; + bool looping_override = false; + bool looping = false; mp3dec_ex_t *mp3d = nullptr; uint32_t frames_mixed = 0; bool active = false; @@ -72,6 +74,9 @@ public: virtual void tag_used_streams() override; + virtual void set_parameter(const StringName &p_name, const Variant &p_value) override; + virtual Variant get_parameter(const StringName &p_name) const override; + AudioStreamPlaybackMP3() {} ~AudioStreamPlaybackMP3(); }; @@ -126,6 +131,8 @@ public: virtual bool is_monophonic() const override; + virtual void get_parameter_list(List<Parameter> *r_parameters) override; + AudioStreamMP3(); virtual ~AudioStreamMP3(); }; diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index 7ec0b697bf..e6003f35df 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -46,8 +46,9 @@ int AudioStreamPlaybackOggVorbis::_mix_internal(AudioFrame *p_buffer, int p_fram int todo = p_frames; int beat_length_frames = -1; - bool beat_loop = vorbis_stream->has_loop(); - if (beat_loop && vorbis_stream->get_bpm() > 0 && vorbis_stream->get_beat_count() > 0) { + bool use_loop = looping_override ? looping : vorbis_stream->loop; + + if (use_loop && vorbis_stream->get_bpm() > 0 && vorbis_stream->get_beat_count() > 0) { beat_length_frames = vorbis_stream->get_beat_count() * vorbis_data->get_sampling_rate() * 60 / vorbis_stream->get_bpm(); } @@ -99,7 +100,7 @@ int AudioStreamPlaybackOggVorbis::_mix_internal(AudioFrame *p_buffer, int p_fram } else **/ - if (beat_loop && beat_length_frames <= (int)frames_mixed) { + if (use_loop && beat_length_frames <= (int)frames_mixed) { // End of file when doing beat-based looping. <= used instead of == because importer editing if (!have_packets_left && !have_samples_left) { //Nothing remaining, so do nothing. @@ -125,7 +126,7 @@ int AudioStreamPlaybackOggVorbis::_mix_internal(AudioFrame *p_buffer, int p_fram if (!have_packets_left && !have_samples_left) { // Actual end of file! bool is_not_empty = mixed > 0 || vorbis_stream->get_length() > 0; - if (vorbis_stream->loop && is_not_empty) { + if (use_loop && is_not_empty) { //loop seek(vorbis_stream->loop_offset); @@ -257,6 +258,25 @@ void AudioStreamPlaybackOggVorbis::tag_used_streams() { vorbis_stream->tag_used(get_playback_position()); } +void AudioStreamPlaybackOggVorbis::set_parameter(const StringName &p_name, const Variant &p_value) { + if (p_name == SNAME("looping")) { + if (p_value == Variant()) { + looping_override = false; + looping = false; + } else { + looping_override = true; + looping = p_value; + } + } +} + +Variant AudioStreamPlaybackOggVorbis::get_parameter(const StringName &p_name) const { + if (looping_override && p_name == SNAME("looping")) { + return looping; + } + return Variant(); +} + void AudioStreamPlaybackOggVorbis::seek(double p_time) { ERR_FAIL_COND(!ready); ERR_FAIL_COND(vorbis_stream.is_null()); @@ -493,6 +513,10 @@ bool AudioStreamOggVorbis::is_monophonic() const { return false; } +void AudioStreamOggVorbis::get_parameter_list(List<Parameter> *r_parameters) { + r_parameters->push_back(Parameter(PropertyInfo(Variant::BOOL, "looping", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE), Variant())); +} + void AudioStreamOggVorbis::_bind_methods() { ClassDB::bind_static_method("AudioStreamOggVorbis", D_METHOD("load_from_buffer", "buffer"), &AudioStreamOggVorbis::load_from_buffer); ClassDB::bind_static_method("AudioStreamOggVorbis", D_METHOD("load_from_file", "path"), &AudioStreamOggVorbis::load_from_file); diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h index 6abaeaaebd..64a7815b57 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.h +++ b/modules/vorbis/audio_stream_ogg_vorbis.h @@ -44,6 +44,8 @@ class AudioStreamPlaybackOggVorbis : public AudioStreamPlaybackResampled { uint32_t frames_mixed = 0; bool active = false; + bool looping_override = false; + bool looping = false; int loops = 0; enum { @@ -95,6 +97,9 @@ public: virtual void tag_used_streams() override; + virtual void set_parameter(const StringName &p_name, const Variant &p_value) override; + virtual Variant get_parameter(const StringName &p_name) const override; + AudioStreamPlaybackOggVorbis() {} ~AudioStreamPlaybackOggVorbis(); }; @@ -152,6 +157,8 @@ public: virtual bool is_monophonic() const override; + virtual void get_parameter_list(List<Parameter> *r_parameters) override; + AudioStreamOggVorbis(); virtual ~AudioStreamOggVorbis(); }; diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index afc5748ac5..a99964c0e0 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -36,6 +36,8 @@ #include "scene/main/window.h" #include "scene/resources/world_2d.h" +#define PARAM_PREFIX "parameters/" + void AudioStreamPlayer2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -222,9 +224,36 @@ void AudioStreamPlayer2D::_update_panning() { last_mix_count = AudioServer::get_singleton()->get_mix_count(); } +void AudioStreamPlayer2D::_update_stream_parameters() { + if (stream.is_null()) { + return; + } + + List<AudioStream::Parameter> parameters; + stream->get_parameter_list(¶meters); + for (const AudioStream::Parameter &K : parameters) { + const PropertyInfo &pi = K.property; + StringName key = PARAM_PREFIX + pi.name; + if (!playback_parameters.has(key)) { + ParameterData pd; + pd.path = pi.name; + pd.value = K.default_value; + playback_parameters.insert(key, pd); + } + } +} + void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) { + if (stream.is_valid()) { + stream->disconnect(SNAME("parameter_list_changed"), callable_mp(this, &AudioStreamPlayer2D::_update_stream_parameters)); + } stop(); stream = p_stream; + _update_stream_parameters(); + if (stream.is_valid()) { + stream->connect(SNAME("parameter_list_changed"), callable_mp(this, &AudioStreamPlayer2D::_update_stream_parameters)); + } + notify_property_list_changed(); } Ref<AudioStream> AudioStreamPlayer2D::get_stream() const { @@ -262,6 +291,10 @@ void AudioStreamPlayer2D::play(float p_from_pos) { Ref<AudioStreamPlayback> stream_playback = stream->instantiate_playback(); ERR_FAIL_COND_MSG(stream_playback.is_null(), "Failed to instantiate playback."); + for (const KeyValue<StringName, ParameterData> &K : playback_parameters) { + stream_playback->set_parameter(K.value.path, K.value.value); + } + stream_playbacks.push_back(stream_playback); setplayback = stream_playback; setplay.set(p_from_pos); @@ -430,6 +463,42 @@ void AudioStreamPlayer2D::_on_bus_renamed(int p_bus_index, const StringName &p_o notify_property_list_changed(); } +bool AudioStreamPlayer2D::_set(const StringName &p_name, const Variant &p_value) { + HashMap<StringName, ParameterData>::Iterator I = playback_parameters.find(p_name); + if (!I) { + return false; + } + ParameterData &pd = I->value; + pd.value = p_value; + for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { + playback->set_parameter(pd.path, pd.value); + } + return true; +} + +bool AudioStreamPlayer2D::_get(const StringName &p_name, Variant &r_ret) const { + HashMap<StringName, ParameterData>::ConstIterator I = playback_parameters.find(p_name); + if (!I) { + return false; + } + + r_ret = I->value.value; + return true; +} + +void AudioStreamPlayer2D::_get_property_list(List<PropertyInfo> *p_list) const { + if (stream.is_null()) { + return; + } + List<AudioStream::Parameter> parameters; + stream->get_parameter_list(¶meters); + for (const AudioStream::Parameter &K : parameters) { + PropertyInfo pi = K.property; + pi.name = PARAM_PREFIX + pi.name; + p_list->push_back(pi); + } +} + void AudioStreamPlayer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer2D::set_stream); ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer2D::get_stream); diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h index 0766f2f77d..267d6a625b 100644 --- a/scene/2d/audio_stream_player_2d.h +++ b/scene/2d/audio_stream_player_2d.h @@ -89,11 +89,23 @@ private: float panning_strength = 1.0f; float cached_global_panning_strength = 0.5f; + struct ParameterData { + StringName path; + Variant value; + }; + + HashMap<StringName, ParameterData> playback_parameters; + void _update_stream_parameters(); + protected: void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + public: void set_stream(Ref<AudioStream> p_stream); Ref<AudioStream> get_stream() const; diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 3971e615a1..bfdbd14cc9 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -37,6 +37,8 @@ #include "scene/main/viewport.h" #include "scene/scene_string_names.h" +#define PARAM_PREFIX "parameters/" + // Based on "A Novel Multichannel Panning Method for Standard and Arbitrary Loudspeaker Configurations" by Ramy Sadek and Chris Kyriakakis (2004) // Speaker-Placement Correction Amplitude Panning (SPCAP) class Spcap { @@ -525,9 +527,35 @@ Vector<AudioFrame> AudioStreamPlayer3D::_update_panning() { return output_volume_vector; } +void AudioStreamPlayer3D::_update_stream_parameters() { + if (stream.is_null()) { + return; + } + List<AudioStream::Parameter> parameters; + stream->get_parameter_list(¶meters); + for (const AudioStream::Parameter &K : parameters) { + const PropertyInfo &pi = K.property; + StringName key = PARAM_PREFIX + pi.name; + if (!playback_parameters.has(key)) { + ParameterData pd; + pd.path = pi.name; + pd.value = K.default_value; + playback_parameters.insert(key, pd); + } + } +} + void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) { + if (stream.is_valid()) { + stream->disconnect(SNAME("parameter_list_changed"), callable_mp(this, &AudioStreamPlayer3D::_update_stream_parameters)); + } stop(); stream = p_stream; + _update_stream_parameters(); + if (stream.is_valid()) { + stream->connect(SNAME("parameter_list_changed"), callable_mp(this, &AudioStreamPlayer3D::_update_stream_parameters)); + } + notify_property_list_changed(); } Ref<AudioStream> AudioStreamPlayer3D::get_stream() const { @@ -579,6 +607,10 @@ void AudioStreamPlayer3D::play(float p_from_pos) { Ref<AudioStreamPlayback> stream_playback = stream->instantiate_playback(); ERR_FAIL_COND_MSG(stream_playback.is_null(), "Failed to instantiate playback."); + for (const KeyValue<StringName, ParameterData> &K : playback_parameters) { + stream_playback->set_parameter(K.value.path, K.value.value); + } + stream_playbacks.push_back(stream_playback); setplayback = stream_playback; setplay.set(p_from_pos); @@ -818,6 +850,42 @@ void AudioStreamPlayer3D::_on_bus_renamed(int p_bus_index, const StringName &p_o notify_property_list_changed(); } +bool AudioStreamPlayer3D::_set(const StringName &p_name, const Variant &p_value) { + HashMap<StringName, ParameterData>::Iterator I = playback_parameters.find(p_name); + if (!I) { + return false; + } + ParameterData &pd = I->value; + pd.value = p_value; + for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { + playback->set_parameter(pd.path, pd.value); + } + return true; +} + +bool AudioStreamPlayer3D::_get(const StringName &p_name, Variant &r_ret) const { + HashMap<StringName, ParameterData>::ConstIterator I = playback_parameters.find(p_name); + if (!I) { + return false; + } + + r_ret = I->value.value; + return true; +} + +void AudioStreamPlayer3D::_get_property_list(List<PropertyInfo> *p_list) const { + if (stream.is_null()) { + return; + } + List<AudioStream::Parameter> parameters; + stream->get_parameter_list(¶meters); + for (const AudioStream::Parameter &K : parameters) { + PropertyInfo pi = K.property; + pi.name = PARAM_PREFIX + pi.name; + p_list->push_back(pi); + } +} + void AudioStreamPlayer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream); ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer3D::get_stream); diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index f20170e63b..facded1b9c 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -121,11 +121,23 @@ private: float panning_strength = 1.0f; float cached_global_panning_strength = 0.5f; + struct ParameterData { + StringName path; + Variant value; + }; + + HashMap<StringName, ParameterData> playback_parameters; + void _update_stream_parameters(); + protected: void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + public: void set_stream(Ref<AudioStream> p_stream); Ref<AudioStream> get_stream() const; diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index f3c986f9b3..bd4731d8dd 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -34,6 +34,8 @@ #include "core/math/audio_frame.h" #include "servers/audio_server.h" +#define PARAM_PREFIX "parameters/" + void AudioStreamPlayer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -88,9 +90,71 @@ void AudioStreamPlayer::_notification(int p_what) { } } +void AudioStreamPlayer::_update_stream_parameters() { + if (stream.is_null()) { + return; + } + List<AudioStream::Parameter> parameters; + stream->get_parameter_list(¶meters); + for (const AudioStream::Parameter &K : parameters) { + const PropertyInfo &pi = K.property; + StringName key = PARAM_PREFIX + pi.name; + if (!playback_parameters.has(key)) { + ParameterData pd; + pd.path = pi.name; + pd.value = K.default_value; + playback_parameters.insert(key, pd); + } + } +} + void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) { + if (stream.is_valid()) { + stream->disconnect(SNAME("parameter_list_changed"), callable_mp(this, &AudioStreamPlayer::_update_stream_parameters)); + } stop(); stream = p_stream; + _update_stream_parameters(); + if (stream.is_valid()) { + stream->connect(SNAME("parameter_list_changed"), callable_mp(this, &AudioStreamPlayer::_update_stream_parameters)); + } + notify_property_list_changed(); +} + +bool AudioStreamPlayer::_set(const StringName &p_name, const Variant &p_value) { + HashMap<StringName, ParameterData>::Iterator I = playback_parameters.find(p_name); + if (!I) { + return false; + } + ParameterData &pd = I->value; + pd.value = p_value; + for (Ref<AudioStreamPlayback> &playback : stream_playbacks) { + playback->set_parameter(pd.path, pd.value); + } + return true; +} + +bool AudioStreamPlayer::_get(const StringName &p_name, Variant &r_ret) const { + HashMap<StringName, ParameterData>::ConstIterator I = playback_parameters.find(p_name); + if (!I) { + return false; + } + + r_ret = I->value.value; + return true; +} + +void AudioStreamPlayer::_get_property_list(List<PropertyInfo> *p_list) const { + if (stream.is_null()) { + return; + } + List<AudioStream::Parameter> parameters; + stream->get_parameter_list(¶meters); + for (const AudioStream::Parameter &K : parameters) { + PropertyInfo pi = K.property; + pi.name = PARAM_PREFIX + pi.name; + p_list->push_back(pi); + } } Ref<AudioStream> AudioStreamPlayer::get_stream() const { @@ -144,6 +208,10 @@ void AudioStreamPlayer::play(float p_from_pos) { Ref<AudioStreamPlayback> stream_playback = stream->instantiate_playback(); ERR_FAIL_COND_MSG(stream_playback.is_null(), "Failed to instantiate playback."); + for (const KeyValue<StringName, ParameterData> &K : playback_parameters) { + stream_playback->set_parameter(K.value.path, K.value.value); + } + AudioServer::get_singleton()->start_playback_stream(stream_playback, bus, _get_volume_vector(), p_from_pos, pitch_scale); stream_playbacks.push_back(stream_playback); active.set(); diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h index 9dbdccdc69..404d6fbebf 100644 --- a/scene/audio/audio_stream_player.h +++ b/scene/audio/audio_stream_player.h @@ -68,11 +68,23 @@ private: Vector<AudioFrame> _get_volume_vector(); + struct ParameterData { + StringName path; + Variant value; + }; + + HashMap<StringName, ParameterData> playback_parameters; + void _update_stream_parameters(); + protected: void _validate_property(PropertyInfo &p_property) const; void _notification(int p_what); static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + public: void set_stream(Ref<AudioStream> p_stream); Ref<AudioStream> get_stream() const; diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 65d88a0eba..3e3a7d2381 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -80,6 +80,16 @@ void AudioStreamPlayback::tag_used_streams() { GDVIRTUAL_CALL(_tag_used_streams); } +void AudioStreamPlayback::set_parameter(const StringName &p_name, const Variant &p_value) { + GDVIRTUAL_CALL(_set_parameter, p_name, p_value); +} + +Variant AudioStreamPlayback::get_parameter(const StringName &p_name) const { + Variant ret; + GDVIRTUAL_CALL(_get_parameter, p_name, ret); + return ret; +} + void AudioStreamPlayback::_bind_methods() { GDVIRTUAL_BIND(_start, "from_pos") GDVIRTUAL_BIND(_stop) @@ -89,6 +99,8 @@ void AudioStreamPlayback::_bind_methods() { GDVIRTUAL_BIND(_seek, "position") GDVIRTUAL_BIND(_mix, "buffer", "rate_scale", "frames"); GDVIRTUAL_BIND(_tag_used_streams); + GDVIRTUAL_BIND(_set_parameter, "name", "value"); + GDVIRTUAL_BIND(_get_parameter, "name"); } ////////////////////////////// @@ -249,6 +261,16 @@ float AudioStream::get_tagged_frame_offset(int p_index) const { return tagged_offsets[p_index]; } +void AudioStream::get_parameter_list(List<Parameter> *r_parameters) { + TypedArray<Dictionary> ret; + GDVIRTUAL_CALL(_get_parameter_list, ret); + for (int i = 0; i < ret.size(); i++) { + Dictionary d = ret[i]; + ERR_CONTINUE(!d.has("default_value")); + r_parameters->push_back(Parameter(PropertyInfo::from_dict(d), d["default_value"])); + } +} + void AudioStream::_bind_methods() { ClassDB::bind_method(D_METHOD("get_length"), &AudioStream::get_length); ClassDB::bind_method(D_METHOD("is_monophonic"), &AudioStream::is_monophonic); @@ -259,6 +281,9 @@ void AudioStream::_bind_methods() { GDVIRTUAL_BIND(_is_monophonic); GDVIRTUAL_BIND(_get_bpm) GDVIRTUAL_BIND(_get_beat_count) + GDVIRTUAL_BIND(_get_parameter_list) + + ADD_SIGNAL(MethodInfo("parameter_list_changed")); } //////////////////////////////// diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 015e89fc8e..f8123fbe15 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -38,6 +38,7 @@ #include "core/object/gdvirtual.gen.inc" #include "core/variant/native_ptr.h" +#include "core/variant/typed_array.h" class AudioStream; @@ -54,6 +55,9 @@ protected: GDVIRTUAL1(_seek, double) GDVIRTUAL3R(int, _mix, GDExtensionPtr<AudioFrame>, float, int) GDVIRTUAL0(_tag_used_streams) + GDVIRTUAL2(_set_parameter, const StringName &, const Variant &) + GDVIRTUAL1RC(Variant, _get_parameter, const StringName &) + public: virtual void start(double p_from_pos = 0.0); virtual void stop(); @@ -66,6 +70,9 @@ public: virtual void tag_used_streams(); + virtual void set_parameter(const StringName &p_name, const Variant &p_value); + virtual Variant get_parameter(const StringName &p_name) const; + virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames); }; @@ -124,6 +131,7 @@ protected: GDVIRTUAL0RC(bool, _has_loop) GDVIRTUAL0RC(int, _get_bar_beats) GDVIRTUAL0RC(int, _get_beat_count) + GDVIRTUAL0RC(TypedArray<Dictionary>, _get_parameter_list) public: virtual Ref<AudioStreamPlayback> instantiate_playback(); @@ -141,6 +149,17 @@ public: uint64_t get_tagged_frame() const; uint32_t get_tagged_frame_count() const; float get_tagged_frame_offset(int p_index) const; + + struct Parameter { + PropertyInfo property; + Variant default_value; + Parameter(const PropertyInfo &p_info = PropertyInfo(), const Variant &p_default_value = Variant()) { + property = p_info; + default_value = p_default_value; + } + }; + + virtual void get_parameter_list(List<Parameter> *r_parameters); }; // Microphone |