diff options
Diffstat (limited to 'modules/vorbis')
-rw-r--r-- | modules/vorbis/audio_stream_ogg_vorbis.cpp | 215 | ||||
-rw-r--r-- | modules/vorbis/audio_stream_ogg_vorbis.h | 66 | ||||
-rw-r--r-- | modules/vorbis/config.py | 4 | ||||
-rw-r--r-- | modules/vorbis/doc_classes/AudioStreamOggVorbis.xml (renamed from modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml) | 12 | ||||
-rw-r--r-- | modules/vorbis/doc_classes/AudioStreamPlaybackOggVorbis.xml (renamed from modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml) | 2 | ||||
-rw-r--r-- | modules/vorbis/register_types.cpp | 6 | ||||
-rw-r--r-- | modules/vorbis/resource_importer_ogg_vorbis.cpp | 98 | ||||
-rw-r--r-- | modules/vorbis/resource_importer_ogg_vorbis.h | 13 |
8 files changed, 298 insertions, 118 deletions
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp index b645a48c88..8315eea614 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp @@ -34,52 +34,114 @@ #include "core/variant/typed_array.h" #include "thirdparty/libogg/ogg/ogg.h" -int AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) { +int AudioStreamPlaybackOggVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) { ERR_FAIL_COND_V(!ready, 0); - ERR_FAIL_COND_V(!active, 0); - int todo = p_frames; + if (!active) { + return 0; + } - int start_buffer = 0; + int todo = p_frames; - int frames_mixed_this_step = 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) { + beat_length_frames = vorbis_stream->get_beat_count() * vorbis_data->get_sampling_rate() * 60 / vorbis_stream->get_bpm(); + } - while (todo && active) { + while (todo > 0 && active) { AudioFrame *buffer = p_buffer; - if (start_buffer > 0) { - buffer = buffer + start_buffer; - } - int mixed = _mix_frames_vorbis(buffer, todo); - if (mixed < 0) { - return 0; + buffer += p_frames - todo; + + int to_mix = todo; + if (beat_length_frames >= 0 && (beat_length_frames - (int)frames_mixed) < to_mix) { + to_mix = MAX(0, beat_length_frames - (int)frames_mixed); } + + int mixed = _mix_frames_vorbis(buffer, to_mix); + ERR_FAIL_COND_V(mixed < 0, 0); todo -= mixed; frames_mixed += mixed; - start_buffer += mixed; + + if (loop_fade_remaining < FADE_SIZE) { + int to_fade = loop_fade_remaining + MIN(FADE_SIZE - loop_fade_remaining, mixed); + for (int i = loop_fade_remaining; i < to_fade; i++) { + buffer[i - loop_fade_remaining] += loop_fade[i] * (float(FADE_SIZE - i) / float(FADE_SIZE)); + } + loop_fade_remaining = to_fade; + } + + if (beat_length_frames >= 0) { + /** + * Length determined by beat length + * This code is commented out because, in practice, it is prefered that the fade + * is done by the transitioner and this stream just goes on until it ends while fading out. + * + * End fade implementation is left here for reference in case at some point this feature + * is desired. + + if (!beat_loop && (int)frames_mixed > beat_length_frames - FADE_SIZE) { + print_line("beat length fade/after mix?"); + //No loop, just fade and finish + for (int i = 0; i < mixed; i++) { + int idx = frames_mixed + i - mixed; + buffer[i] *= 1.0 - float(MAX(0, (idx - (beat_length_frames - FADE_SIZE)))) / float(FADE_SIZE); + } + if ((int)frames_mixed == beat_length_frames) { + for (int i = p_frames - todo; i < p_frames; i++) { + p_buffer[i] = AudioFrame(0, 0); + } + active = false; + break; + } + } else + **/ + + if (beat_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. + loop_fade_remaining = FADE_SIZE; + } else { + // Add some loop fade; + int faded_mix = _mix_frames_vorbis(loop_fade, FADE_SIZE); + + for (int i = faded_mix; i < FADE_SIZE; i++) { + // In case lesss was mixed, pad with zeros + loop_fade[i] = AudioFrame(0, 0); + } + loop_fade_remaining = 0; + } + + seek(vorbis_stream->loop_offset); + loops++; + // We still have buffer to fill, start from this element in the next iteration. + continue; + } + } + if (!have_packets_left && !have_samples_left) { - //end of file! + // Actual end of file! bool is_not_empty = mixed > 0 || vorbis_stream->get_length() > 0; if (vorbis_stream->loop && is_not_empty) { //loop seek(vorbis_stream->loop_offset); loops++; - // we still have buffer to fill, start from this element in the next iteration. - start_buffer = p_frames - todo; + // We still have buffer to fill, start from this element in the next iteration. + } else { - frames_mixed_this_step = p_frames - todo; for (int i = p_frames - todo; i < p_frames; i++) { p_buffer[i] = AudioFrame(0, 0); } active = false; - todo = 0; } } } - return frames_mixed_this_step; + return p_frames - todo; } -int AudioStreamPlaybackOGGVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p_frames) { +int AudioStreamPlaybackOggVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p_frames) { ERR_FAIL_COND_V(!ready, 0); if (!have_samples_left) { ogg_packet *packet = nullptr; @@ -122,18 +184,18 @@ int AudioStreamPlaybackOGGVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p return frames; } -float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() { +float AudioStreamPlaybackOggVorbis::get_stream_sampling_rate() { return vorbis_data->get_sampling_rate(); } -bool AudioStreamPlaybackOGGVorbis::_alloc_vorbis() { +bool AudioStreamPlaybackOggVorbis::_alloc_vorbis() { vorbis_info_init(&info); info_is_allocated = true; vorbis_comment_init(&comment); comment_is_allocated = true; ERR_FAIL_COND_V(vorbis_data.is_null(), false); - vorbis_data_playback = vorbis_data->instance_playback(); + vorbis_data_playback = vorbis_data->instantiate_playback(); ogg_packet *packet; int err; @@ -161,31 +223,36 @@ bool AudioStreamPlaybackOGGVorbis::_alloc_vorbis() { return true; } -void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) { +void AudioStreamPlaybackOggVorbis::start(float p_from_pos) { ERR_FAIL_COND(!ready); + loop_fade_remaining = FADE_SIZE; active = true; seek(p_from_pos); loops = 0; begin_resample(); } -void AudioStreamPlaybackOGGVorbis::stop() { +void AudioStreamPlaybackOggVorbis::stop() { active = false; } -bool AudioStreamPlaybackOGGVorbis::is_playing() const { +bool AudioStreamPlaybackOggVorbis::is_playing() const { return active; } -int AudioStreamPlaybackOGGVorbis::get_loop_count() const { +int AudioStreamPlaybackOggVorbis::get_loop_count() const { return loops; } -float AudioStreamPlaybackOGGVorbis::get_playback_position() const { +float AudioStreamPlaybackOggVorbis::get_playback_position() const { return float(frames_mixed) / vorbis_data->get_sampling_rate(); } -void AudioStreamPlaybackOGGVorbis::seek(float p_time) { +void AudioStreamPlaybackOggVorbis::tag_used_streams() { + vorbis_stream->tag_used(get_playback_position()); +} + +void AudioStreamPlaybackOggVorbis::seek(float p_time) { ERR_FAIL_COND(!ready); ERR_FAIL_COND(vorbis_stream.is_null()); if (!active) { @@ -303,7 +370,7 @@ void AudioStreamPlaybackOGGVorbis::seek(float p_time) { } } -AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() { +AudioStreamPlaybackOggVorbis::~AudioStreamPlaybackOggVorbis() { if (block_is_allocated) { vorbis_block_clear(&block); } @@ -318,13 +385,13 @@ AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() { } } -Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() { - Ref<AudioStreamPlaybackOGGVorbis> ovs; +Ref<AudioStreamPlayback> AudioStreamOggVorbis::instantiate_playback() { + Ref<AudioStreamPlaybackOggVorbis> ovs; ERR_FAIL_COND_V(packet_sequence.is_null(), nullptr); ovs.instantiate(); - ovs->vorbis_stream = Ref<AudioStreamOGGVorbis>(this); + ovs->vorbis_stream = Ref<AudioStreamOggVorbis>(this); ovs->vorbis_data = packet_sequence; ovs->frames_mixed = 0; ovs->active = false; @@ -336,11 +403,11 @@ Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() { return nullptr; } -String AudioStreamOGGVorbis::get_stream_name() const { +String AudioStreamOggVorbis::get_stream_name() const { return ""; //return stream_name; } -void AudioStreamOGGVorbis::maybe_update_info() { +void AudioStreamOggVorbis::maybe_update_info() { ERR_FAIL_COND(packet_sequence.is_null()); vorbis_info info; @@ -350,7 +417,7 @@ void AudioStreamOGGVorbis::maybe_update_info() { vorbis_info_init(&info); vorbis_comment_init(&comment); - Ref<OGGPacketSequencePlayback> packet_sequence_playback = packet_sequence->instance_playback(); + Ref<OggPacketSequencePlayback> packet_sequence_playback = packet_sequence->instantiate_playback(); for (int i = 0; i < 3; i++) { ogg_packet *packet; @@ -376,57 +443,99 @@ void AudioStreamOGGVorbis::maybe_update_info() { vorbis_info_clear(&info); } -void AudioStreamOGGVorbis::set_packet_sequence(Ref<OGGPacketSequence> p_packet_sequence) { +void AudioStreamOggVorbis::set_packet_sequence(Ref<OggPacketSequence> p_packet_sequence) { packet_sequence = p_packet_sequence; if (packet_sequence.is_valid()) { maybe_update_info(); } } -Ref<OGGPacketSequence> AudioStreamOGGVorbis::get_packet_sequence() const { +Ref<OggPacketSequence> AudioStreamOggVorbis::get_packet_sequence() const { return packet_sequence; } -void AudioStreamOGGVorbis::set_loop(bool p_enable) { +void AudioStreamOggVorbis::set_loop(bool p_enable) { loop = p_enable; } -bool AudioStreamOGGVorbis::has_loop() const { +bool AudioStreamOggVorbis::has_loop() const { return loop; } -void AudioStreamOGGVorbis::set_loop_offset(float p_seconds) { +void AudioStreamOggVorbis::set_loop_offset(float p_seconds) { loop_offset = p_seconds; } -float AudioStreamOGGVorbis::get_loop_offset() const { +float AudioStreamOggVorbis::get_loop_offset() const { return loop_offset; } -float AudioStreamOGGVorbis::get_length() const { +float AudioStreamOggVorbis::get_length() const { ERR_FAIL_COND_V(packet_sequence.is_null(), 0); return packet_sequence->get_length(); } -bool AudioStreamOGGVorbis::is_monophonic() const { +void AudioStreamOggVorbis::set_bpm(double p_bpm) { + ERR_FAIL_COND(p_bpm < 0); + bpm = p_bpm; + emit_changed(); +} + +double AudioStreamOggVorbis::get_bpm() const { + return bpm; +} + +void AudioStreamOggVorbis::set_beat_count(int p_beat_count) { + ERR_FAIL_COND(p_beat_count < 0); + beat_count = p_beat_count; + emit_changed(); +} + +int AudioStreamOggVorbis::get_beat_count() const { + return beat_count; +} + +void AudioStreamOggVorbis::set_bar_beats(int p_bar_beats) { + ERR_FAIL_COND(p_bar_beats < 2); + bar_beats = p_bar_beats; + emit_changed(); +} + +int AudioStreamOggVorbis::get_bar_beats() const { + return bar_beats; +} + +bool AudioStreamOggVorbis::is_monophonic() const { return false; } -void AudioStreamOGGVorbis::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_packet_sequence", "packet_sequence"), &AudioStreamOGGVorbis::set_packet_sequence); - ClassDB::bind_method(D_METHOD("get_packet_sequence"), &AudioStreamOGGVorbis::get_packet_sequence); +void AudioStreamOggVorbis::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_packet_sequence", "packet_sequence"), &AudioStreamOggVorbis::set_packet_sequence); + ClassDB::bind_method(D_METHOD("get_packet_sequence"), &AudioStreamOggVorbis::get_packet_sequence); + + ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamOggVorbis::set_loop); + ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamOggVorbis::has_loop); + + ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamOggVorbis::set_loop_offset); + ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOggVorbis::get_loop_offset); + + ClassDB::bind_method(D_METHOD("set_bpm", "bpm"), &AudioStreamOggVorbis::set_bpm); + ClassDB::bind_method(D_METHOD("get_bpm"), &AudioStreamOggVorbis::get_bpm); - ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamOGGVorbis::set_loop); - ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamOGGVorbis::has_loop); + ClassDB::bind_method(D_METHOD("set_beat_count", "count"), &AudioStreamOggVorbis::set_beat_count); + ClassDB::bind_method(D_METHOD("get_beat_count"), &AudioStreamOggVorbis::get_beat_count); - ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamOGGVorbis::set_loop_offset); - ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOGGVorbis::get_loop_offset); + ClassDB::bind_method(D_METHOD("set_bar_beats", "count"), &AudioStreamOggVorbis::set_bar_beats); + ClassDB::bind_method(D_METHOD("get_bar_beats"), &AudioStreamOggVorbis::get_bar_beats); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "packet_sequence", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_packet_sequence", "get_packet_sequence"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bpm", PROPERTY_HINT_RANGE, "0,400,0.01,or_greater"), "set_bpm", "get_bpm"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "beat_count", PROPERTY_HINT_RANGE, "0,512,1,or_greater"), "set_beat_count", "get_beat_count"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bar_beats", PROPERTY_HINT_RANGE, "2,32,1,or_greater"), "set_bar_beats", "get_bar_beats"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset"), "set_loop_offset", "get_loop_offset"); } -AudioStreamOGGVorbis::AudioStreamOGGVorbis() {} +AudioStreamOggVorbis::AudioStreamOggVorbis() {} -AudioStreamOGGVorbis::~AudioStreamOGGVorbis() {} +AudioStreamOggVorbis::~AudioStreamOggVorbis() {} diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h index b09ef9ff5d..0350e1f761 100644 --- a/modules/vorbis/audio_stream_ogg_vorbis.h +++ b/modules/vorbis/audio_stream_ogg_vorbis.h @@ -28,23 +28,29 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AUDIO_STREAM_LIBVORBIS_H -#define AUDIO_STREAM_LIBVORBIS_H +#ifndef AUDIO_STREAM_OGG_VORBIS_H +#define AUDIO_STREAM_OGG_VORBIS_H #include "core/variant/variant.h" #include "modules/ogg/ogg_packet_sequence.h" #include "servers/audio/audio_stream.h" #include "thirdparty/libvorbis/vorbis/codec.h" -class AudioStreamOGGVorbis; +class AudioStreamOggVorbis; -class AudioStreamPlaybackOGGVorbis : public AudioStreamPlaybackResampled { - GDCLASS(AudioStreamPlaybackOGGVorbis, AudioStreamPlaybackResampled); +class AudioStreamPlaybackOggVorbis : public AudioStreamPlaybackResampled { + GDCLASS(AudioStreamPlaybackOggVorbis, AudioStreamPlaybackResampled); uint32_t frames_mixed = 0; bool active = false; int loops = 0; + enum { + FADE_SIZE = 256 + }; + AudioFrame loop_fade[FADE_SIZE]; + int loop_fade_remaining = FADE_SIZE; + vorbis_info info; vorbis_comment comment; vorbis_dsp_state dsp_state; @@ -60,12 +66,13 @@ class AudioStreamPlaybackOGGVorbis : public AudioStreamPlaybackResampled { bool have_samples_left = false; bool have_packets_left = false; - friend class AudioStreamOGGVorbis; + friend class AudioStreamOggVorbis; - Ref<OGGPacketSequence> vorbis_data; - Ref<OGGPacketSequencePlayback> vorbis_data_playback; - Ref<AudioStreamOGGVorbis> vorbis_stream; + Ref<OggPacketSequence> vorbis_data; + Ref<OggPacketSequencePlayback> vorbis_data_playback; + Ref<AudioStreamOggVorbis> vorbis_stream; + int _mix_frames(AudioFrame *p_buffer, int p_frames); int _mix_frames_vorbis(AudioFrame *p_buffer, int p_frames); // Allocates vorbis data structures. Returns true upon success, false on failure. @@ -85,16 +92,18 @@ public: virtual float get_playback_position() const override; virtual void seek(float p_time) override; - AudioStreamPlaybackOGGVorbis() {} - ~AudioStreamPlaybackOGGVorbis(); + virtual void tag_used_streams() override; + + AudioStreamPlaybackOggVorbis() {} + ~AudioStreamPlaybackOggVorbis(); }; -class AudioStreamOGGVorbis : public AudioStream { - GDCLASS(AudioStreamOGGVorbis, AudioStream); +class AudioStreamOggVorbis : public AudioStream { + GDCLASS(AudioStreamOggVorbis, AudioStream); OBJ_SAVE_TYPE(AudioStream); // Saves derived classes with common type so they can be interchanged. RES_BASE_EXTENSION("oggvorbisstr"); - friend class AudioStreamPlaybackOGGVorbis; + friend class AudioStreamPlaybackOggVorbis; int channels = 1; float length = 0.0; @@ -105,30 +114,43 @@ class AudioStreamOGGVorbis : public AudioStream { // Also causes allocation and deallocation. void maybe_update_info(); - Ref<OGGPacketSequence> packet_sequence; + Ref<OggPacketSequence> packet_sequence; + + double bpm = 0; + int beat_count = 0; + int bar_beats = 4; protected: static void _bind_methods(); public: void set_loop(bool p_enable); - bool has_loop() const; + virtual bool has_loop() const override; void set_loop_offset(float p_seconds); float get_loop_offset() const; - virtual Ref<AudioStreamPlayback> instance_playback() override; + void set_bpm(double p_bpm); + virtual double get_bpm() const override; + + void set_beat_count(int p_beat_count); + virtual int get_beat_count() const override; + + void set_bar_beats(int p_bar_beats); + virtual int get_bar_beats() const override; + + virtual Ref<AudioStreamPlayback> instantiate_playback() override; virtual String get_stream_name() const override; - void set_packet_sequence(Ref<OGGPacketSequence> p_packet_sequence); - Ref<OGGPacketSequence> get_packet_sequence() const; + void set_packet_sequence(Ref<OggPacketSequence> p_packet_sequence); + Ref<OggPacketSequence> get_packet_sequence() const; virtual float get_length() const override; //if supported, otherwise return 0 virtual bool is_monophonic() const override; - AudioStreamOGGVorbis(); - virtual ~AudioStreamOGGVorbis(); + AudioStreamOggVorbis(); + virtual ~AudioStreamOggVorbis(); }; -#endif // AUDIO_STREAM_LIBVORBIS_H +#endif // AUDIO_STREAM_OGG_VORBIS_H diff --git a/modules/vorbis/config.py b/modules/vorbis/config.py index 978eccb29f..7ce885a37a 100644 --- a/modules/vorbis/config.py +++ b/modules/vorbis/config.py @@ -8,8 +8,8 @@ def configure(env): def get_doc_classes(): return [ - "AudioStreamOGGVorbis", - "AudioStreamPlaybackOGGVorbis", + "AudioStreamOggVorbis", + "AudioStreamPlaybackOggVorbis", ] diff --git a/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml index 2f210a6cb4..225ea4e6ae 100644 --- a/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml +++ b/modules/vorbis/doc_classes/AudioStreamOggVorbis.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamOGGVorbis" inherits="AudioStream" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> +<class name="AudioStreamOggVorbis" inherits="AudioStream" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> @@ -7,14 +7,20 @@ <tutorials> </tutorials> <members> + <member name="bar_beats" type="int" setter="set_bar_beats" getter="get_bar_beats" default="4"> + </member> + <member name="beat_count" type="int" setter="set_beat_count" getter="get_beat_count" default="0"> + </member> + <member name="bpm" type="float" setter="set_bpm" getter="get_bpm" default="0.0"> + </member> <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false"> If [code]true[/code], the stream will automatically loop when it reaches the end. </member> <member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset" default="0.0"> Time in seconds at which the stream starts after being looped. </member> - <member name="packet_sequence" type="OGGPacketSequence" setter="set_packet_sequence" getter="get_packet_sequence"> - Contains the raw OGG data for this stream. + <member name="packet_sequence" type="OggPacketSequence" setter="set_packet_sequence" getter="get_packet_sequence"> + Contains the raw Ogg data for this stream. </member> </members> </class> diff --git a/modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml b/modules/vorbis/doc_classes/AudioStreamPlaybackOggVorbis.xml index 68aa46147f..0879c773ac 100644 --- a/modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml +++ b/modules/vorbis/doc_classes/AudioStreamPlaybackOggVorbis.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamPlaybackOGGVorbis" inherits="AudioStreamPlaybackResampled" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> +<class name="AudioStreamPlaybackOggVorbis" inherits="AudioStreamPlaybackResampled" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd"> <brief_description> </brief_description> <description> diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp index 7f81f88cdb..84a71fe82d 100644 --- a/modules/vorbis/register_types.cpp +++ b/modules/vorbis/register_types.cpp @@ -40,13 +40,13 @@ void initialize_vorbis_module(ModuleInitializationLevel p_level) { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - Ref<ResourceImporterOGGVorbis> ogg_vorbis_importer; + Ref<ResourceImporterOggVorbis> ogg_vorbis_importer; ogg_vorbis_importer.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(ogg_vorbis_importer); } #endif - GDREGISTER_CLASS(AudioStreamOGGVorbis); - GDREGISTER_CLASS(AudioStreamPlaybackOGGVorbis); + GDREGISTER_CLASS(AudioStreamOggVorbis); + GDREGISTER_CLASS(AudioStreamPlaybackOggVorbis); } void uninitialize_vorbis_module(ModuleInitializationLevel p_level) { diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp index 7ee6446313..bf5f7206b8 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp @@ -30,56 +30,59 @@ #include "resource_importer_ogg_vorbis.h" -#include "audio_stream_ogg_vorbis.h" #include "core/io/file_access.h" #include "core/io/resource_saver.h" #include "scene/resources/texture.h" #include "thirdparty/libogg/ogg/ogg.h" #include "thirdparty/libvorbis/vorbis/codec.h" -String ResourceImporterOGGVorbis::get_importer_name() const { +#ifdef TOOLS_ENABLED +#include "editor/import/audio_stream_import_settings.h" +#endif + +String ResourceImporterOggVorbis::get_importer_name() const { return "oggvorbisstr"; } -String ResourceImporterOGGVorbis::get_visible_name() const { +String ResourceImporterOggVorbis::get_visible_name() const { return "oggvorbisstr"; } -void ResourceImporterOGGVorbis::get_recognized_extensions(List<String> *p_extensions) const { +void ResourceImporterOggVorbis::get_recognized_extensions(List<String> *p_extensions) const { p_extensions->push_back("ogg"); } -String ResourceImporterOGGVorbis::get_save_extension() const { +String ResourceImporterOggVorbis::get_save_extension() const { return "oggvorbisstr"; } -String ResourceImporterOGGVorbis::get_resource_type() const { - return "AudioStreamOGGVorbis"; +String ResourceImporterOggVorbis::get_resource_type() const { + return "AudioStreamOggVorbis"; } -bool ResourceImporterOGGVorbis::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const { +bool ResourceImporterOggVorbis::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const { return true; } -int ResourceImporterOGGVorbis::get_preset_count() const { +int ResourceImporterOggVorbis::get_preset_count() const { return 0; } -String ResourceImporterOGGVorbis::get_preset_name(int p_idx) const { +String ResourceImporterOggVorbis::get_preset_name(int p_idx) const { return String(); } -void ResourceImporterOGGVorbis::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { +void ResourceImporterOggVorbis::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "bpm", PROPERTY_HINT_RANGE, "0,400,0.01,or_greater"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "beat_count", PROPERTY_HINT_RANGE, "0,512,or_greater"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "bar_beats", PROPERTY_HINT_RANGE, "2,32,or_greater"), 4)); } -Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { - bool loop = p_options["loop"]; - float loop_offset = p_options["loop_offset"]; - - Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ); - ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'."); +Ref<AudioStreamOggVorbis> ResourceImporterOggVorbis::import_ogg_vorbis(const String &p_path) { + Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ); + ERR_FAIL_COND_V_MSG(f.is_null(), Ref<AudioStreamOggVorbis>(), "Cannot open file '" + p_path + "'."); uint64_t len = f->get_length(); @@ -89,10 +92,10 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin f->get_buffer(w, len); - Ref<AudioStreamOGGVorbis> ogg_vorbis_stream; + Ref<AudioStreamOggVorbis> ogg_vorbis_stream; ogg_vorbis_stream.instantiate(); - Ref<OGGPacketSequence> ogg_packet_sequence; + Ref<OggPacketSequence> ogg_packet_sequence; ogg_packet_sequence.instantiate(); ogg_stream_state stream_state; @@ -107,16 +110,16 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin size_t packet_count = 0; bool done = false; while (!done) { - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); while (ogg_sync_pageout(&sync_state, &page) != 1) { if (cursor >= len) { done = true; break; } - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); char *sync_buf = ogg_sync_buffer(&sync_state, OGG_SYNC_BUFFER_SIZE); - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); - ERR_FAIL_COND_V(cursor > len, Error::ERR_INVALID_DATA); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V(cursor > len, Ref<AudioStreamOggVorbis>()); size_t copy_size = len - cursor; if (copy_size > OGG_SYNC_BUFFER_SIZE) { copy_size = OGG_SYNC_BUFFER_SIZE; @@ -124,22 +127,22 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin memcpy(sync_buf, &file_data[cursor], copy_size); ogg_sync_wrote(&sync_state, copy_size); cursor += copy_size; - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); } if (done) { break; } - ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Ref<AudioStreamOggVorbis>(), "Ogg sync error " + itos(err)); // Have a page now. if (!initialized_stream) { if (ogg_stream_init(&stream_state, ogg_page_serialno(&page))) { - ERR_FAIL_V_MSG(Error::ERR_OUT_OF_MEMORY, "Failed allocating memory for OGG Vorbis stream."); + ERR_FAIL_V_MSG(Ref<AudioStreamOggVorbis>(), "Failed allocating memory for Ogg Vorbis stream."); } initialized_stream = true; } ogg_stream_pagein(&stream_state, &page); - ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Error::ERR_INVALID_DATA, "Ogg stream error " + itos(err)); + ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Ref<AudioStreamOggVorbis>(), "Ogg stream error " + itos(err)); int desync_iters = 0; Vector<Vector<uint8_t>> packet_data; @@ -150,7 +153,7 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin if (err == -1) { // According to the docs this is usually recoverable, but don't sit here spinning forever. desync_iters++; - ERR_FAIL_COND_V_MSG(desync_iters > 100, Error::ERR_INVALID_DATA, "Packet sync issue during ogg import"); + ERR_FAIL_COND_V_MSG(desync_iters > 100, Ref<AudioStreamOggVorbis>(), "Packet sync issue during Ogg import"); continue; } else if (err == 0) { // Not enough data to fully reconstruct a packet. Go on to the next page. @@ -183,15 +186,48 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin ogg_sync_clear(&sync_state); if (ogg_packet_sequence->get_packet_granule_positions().is_empty()) { - ERR_FAIL_V_MSG(Error::ERR_FILE_CORRUPT, "OGG Vorbis decoding failed. Check that your data is a valid OGG Vorbis audio stream."); + ERR_FAIL_V_MSG(Ref<AudioStreamOggVorbis>(), "Ogg Vorbis decoding failed. Check that your data is a valid Ogg Vorbis audio stream."); } ogg_vorbis_stream->set_packet_sequence(ogg_packet_sequence); + + return ogg_vorbis_stream; +} + +#ifdef TOOLS_ENABLED + +bool ResourceImporterOggVorbis::has_advanced_options() const { + return true; +} + +void ResourceImporterOggVorbis::show_advanced_options(const String &p_path) { + Ref<AudioStreamOggVorbis> ogg_stream = import_ogg_vorbis(p_path); + if (ogg_stream.is_valid()) { + AudioStreamImportSettings::get_singleton()->edit(p_path, "oggvorbisstr", ogg_stream); + } +} +#endif + +Error ResourceImporterOggVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { + bool loop = p_options["loop"]; + float loop_offset = p_options["loop_offset"]; + double bpm = p_options["bpm"]; + int beat_count = p_options["beat_count"]; + int bar_beats = p_options["bar_beats"]; + + Ref<AudioStreamOggVorbis> ogg_vorbis_stream = import_ogg_vorbis(p_source_file); + if (ogg_vorbis_stream.is_null()) { + return ERR_CANT_OPEN; + } + ogg_vorbis_stream->set_loop(loop); ogg_vorbis_stream->set_loop_offset(loop_offset); + ogg_vorbis_stream->set_bpm(bpm); + ogg_vorbis_stream->set_beat_count(beat_count); + ogg_vorbis_stream->set_bar_beats(bar_beats); - return ResourceSaver::save(p_save_path + ".oggvorbisstr", ogg_vorbis_stream); + return ResourceSaver::save(ogg_vorbis_stream, p_save_path + ".oggvorbisstr"); } -ResourceImporterOGGVorbis::ResourceImporterOGGVorbis() { +ResourceImporterOggVorbis::ResourceImporterOggVorbis() { } diff --git a/modules/vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h index 3b4a68a1fd..a1a970e2cc 100644 --- a/modules/vorbis/resource_importer_ogg_vorbis.h +++ b/modules/vorbis/resource_importer_ogg_vorbis.h @@ -31,10 +31,11 @@ #ifndef RESOURCE_IMPORTER_OGG_VORBIS_H #define RESOURCE_IMPORTER_OGG_VORBIS_H +#include "audio_stream_ogg_vorbis.h" #include "core/io/resource_importer.h" -class ResourceImporterOGGVorbis : public ResourceImporter { - GDCLASS(ResourceImporterOGGVorbis, ResourceImporter); +class ResourceImporterOggVorbis : public ResourceImporter { + GDCLASS(ResourceImporterOggVorbis, ResourceImporter); enum { OGG_SYNC_BUFFER_SIZE = 8192, @@ -43,7 +44,13 @@ class ResourceImporterOGGVorbis : public ResourceImporter { private: // virtual int get_samples_in_packet(Vector<uint8_t> p_packet) = 0; + static Ref<AudioStreamOggVorbis> import_ogg_vorbis(const String &p_path); + public: +#ifdef TOOLS_ENABLED + virtual bool has_advanced_options() const override; + virtual void show_advanced_options(const String &p_path) override; +#endif virtual void get_recognized_extensions(List<String> *p_extensions) const override; virtual String get_save_extension() const override; virtual String get_resource_type() const override; @@ -56,7 +63,7 @@ public: virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; - ResourceImporterOGGVorbis(); + ResourceImporterOggVorbis(); }; #endif // RESOURCE_IMPORTER_OGG_VORBIS_H |