summaryrefslogtreecommitdiff
path: root/modules/vorbis
diff options
context:
space:
mode:
Diffstat (limited to 'modules/vorbis')
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp215
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.h66
-rw-r--r--modules/vorbis/config.py4
-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.cpp6
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.cpp98
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.h13
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