/**************************************************************************/ /* audio_stream_interactive.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /**************************************************************************/ /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ #ifndef AUDIO_STREAM_INTERACTIVE_H #define AUDIO_STREAM_INTERACTIVE_H #include "servers/audio/audio_stream.h" class AudioStreamPlaybackInteractive; class AudioStreamInteractive : public AudioStream { GDCLASS(AudioStreamInteractive, AudioStream) OBJ_SAVE_TYPE(AudioStream) public: enum TransitionFromTime { TRANSITION_FROM_TIME_IMMEDIATE, TRANSITION_FROM_TIME_NEXT_BEAT, TRANSITION_FROM_TIME_NEXT_BAR, TRANSITION_FROM_TIME_END, TRANSITION_FROM_TIME_MAX }; enum TransitionToTime { TRANSITION_TO_TIME_SAME_POSITION, TRANSITION_TO_TIME_START, TRANSITION_TO_TIME_PREVIOUS_POSITION, TRANSITION_TO_TIME_MAX, }; enum FadeMode { FADE_DISABLED, FADE_IN, FADE_OUT, FADE_CROSS, FADE_AUTOMATIC, FADE_MAX }; enum AutoAdvanceMode { AUTO_ADVANCE_DISABLED, AUTO_ADVANCE_ENABLED, AUTO_ADVANCE_RETURN_TO_HOLD, }; enum { CLIP_ANY = -1 }; private: friend class AudioStreamPlaybackInteractive; int sample_rate = 44100; bool stereo = true; int initial_clip = 0; double time = 0; enum { MAX_CLIPS = 63, // Because we use bitmasks for transition matching. MAX_TRANSITIONS = 63, }; struct Clip { StringName name; Ref stream; AutoAdvanceMode auto_advance = AUTO_ADVANCE_DISABLED; int auto_advance_next_clip = 0; }; Clip clips[MAX_CLIPS]; struct Transition { TransitionFromTime from_time = TRANSITION_FROM_TIME_NEXT_BEAT; TransitionToTime to_time = TRANSITION_TO_TIME_START; FadeMode fade_mode = FADE_AUTOMATIC; int fade_beats = 1; bool use_filler_clip = false; int filler_clip = 0; bool hold_previous = false; }; struct TransitionKey { uint32_t from_clip; uint32_t to_clip; bool operator==(const TransitionKey &p_key) const { return from_clip == p_key.from_clip && to_clip == p_key.to_clip; } TransitionKey(uint32_t p_from_clip = 0, uint32_t p_to_clip = 0) { from_clip = p_from_clip; to_clip = p_to_clip; } }; struct TransitionKeyHasher { static _FORCE_INLINE_ uint32_t hash(const TransitionKey &p_key) { uint32_t h = hash_murmur3_one_32(p_key.from_clip); return hash_murmur3_one_32(p_key.to_clip, h); } }; HashMap transition_map; uint64_t version = 1; // Used to stop playback instances for incompatibility. int clip_count = 0; HashSet playbacks; #ifdef TOOLS_ENABLED mutable String stream_name_cache; String _get_streams_hint() const; PackedStringArray _get_linked_undo_properties(const String &p_property, const Variant &p_new_value) const; void _inspector_array_swap_clip(uint32_t p_item_a, uint32_t p_item_b); #endif void _set_transitions(const Dictionary &p_transitions); Dictionary _get_transitions() const; public: // CLIPS void set_clip_count(int p_count); int get_clip_count() const; void set_initial_clip(int p_clip); int get_initial_clip() const; void set_clip_name(int p_clip, const StringName &p_name); StringName get_clip_name(int p_clip) const; void set_clip_stream(int p_clip, const Ref &p_stream); Ref get_clip_stream(int p_clip) const; void set_clip_auto_advance(int p_clip, AutoAdvanceMode p_mode); AutoAdvanceMode get_clip_auto_advance(int p_clip) const; void set_clip_auto_advance_next_clip(int p_clip, int p_index); int get_clip_auto_advance_next_clip(int p_clip) const; // TRANSITIONS void add_transition(int p_from_clip, int p_to_clip, TransitionFromTime p_from_time, TransitionToTime p_to_time, FadeMode p_fade_mode, float p_fade_beats, bool p_use_filler_flip = false, int p_filler_clip = -1, bool p_hold_previous = false); TransitionFromTime get_transition_from_time(int p_from_clip, int p_to_clip) const; TransitionToTime get_transition_to_time(int p_from_clip, int p_to_clip) const; FadeMode get_transition_fade_mode(int p_from_clip, int p_to_clip) const; float get_transition_fade_beats(int p_from_clip, int p_to_clip) const; bool is_transition_using_filler_clip(int p_from_clip, int p_to_clip) const; int get_transition_filler_clip(int p_from_clip, int p_to_clip) const; bool is_transition_holding_previous(int p_from_clip, int p_to_clip) const; bool has_transition(int p_from_clip, int p_to_clip) const; void erase_transition(int p_from_clip, int p_to_clip); PackedInt32Array get_transition_list() const; virtual Ref instantiate_playback() override; virtual String get_stream_name() const override; virtual double get_length() const override { return 0; } AudioStreamInteractive(); protected: virtual void get_parameter_list(List *r_parameters) override; static void _bind_methods(); void _validate_property(PropertyInfo &r_property) const; }; VARIANT_ENUM_CAST(AudioStreamInteractive::TransitionFromTime) VARIANT_ENUM_CAST(AudioStreamInteractive::TransitionToTime) VARIANT_ENUM_CAST(AudioStreamInteractive::AutoAdvanceMode) VARIANT_ENUM_CAST(AudioStreamInteractive::FadeMode) class AudioStreamPlaybackInteractive : public AudioStreamPlayback { GDCLASS(AudioStreamPlaybackInteractive, AudioStreamPlayback) friend class AudioStreamInteractive; private: Ref stream; uint64_t version = 0; enum { BUFFER_SIZE = 1024 }; AudioFrame mix_buffer[BUFFER_SIZE]; AudioFrame temp_buffer[BUFFER_SIZE]; struct State { Ref stream; Ref playback; bool active = false; double fade_wait = 0; // Time to wait until fade kicks-in double fade_volume = 1.0; double fade_speed = 0; // Fade speed, negative or positive int auto_advance = -1; bool first_mix = true; double previous_position = 0; void reset_fade() { fade_wait = 0; fade_volume = 1.0; fade_speed = 0; } }; State states[AudioStreamInteractive::MAX_CLIPS]; int playback_current = -1; bool active = false; int return_memory = -1; void _mix_internal(int p_frames); void _mix_internal_state(int p_state_idx, int p_frames); void _queue(int p_to_clip_index, bool p_is_auto_advance); int switch_request = -1; protected: static void _bind_methods(); public: virtual void start(double p_from_pos = 0.0) override; virtual void stop() override; virtual bool is_playing() const override; virtual int get_loop_count() const override; // times it looped virtual double get_playback_position() const override; virtual void seek(double p_time) override; virtual int mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) override; virtual void tag_used_streams() override; void switch_to_clip_by_name(const StringName &p_name); void switch_to_clip(int p_index); virtual void set_parameter(const StringName &p_name, const Variant &p_value) override; virtual Variant get_parameter(const StringName &p_name) const override; AudioStreamPlaybackInteractive(); ~AudioStreamPlaybackInteractive(); }; #endif // AUDIO_STREAM_INTERACTIVE_H