From d1ddee225830b28171de031bd1f1918ced21b38f Mon Sep 17 00:00:00 2001 From: reduz Date: Thu, 21 Jul 2022 01:00:58 +0200 Subject: Implement BPM support Based on #62896, only implements the BPM support part. * Implements BPM support in the AudioStreamOGG/MP3 importers. * Can select BPM/Bar Size and total beats in a song file, as well as edit looping points. * Looping is now BPM aware * Added a special importer UI for configuring this. * Added a special preview showing the audio waveform as well as the playback position in the resource picker. * Renamed `AudioStream::instance` to `instantiate` for correctness. --- editor/plugins/audio_stream_editor_plugin.cpp | 285 -------------------------- editor/plugins/audio_stream_editor_plugin.h | 91 -------- editor/plugins/editor_preview_plugins.cpp | 2 +- 3 files changed, 1 insertion(+), 377 deletions(-) delete mode 100644 editor/plugins/audio_stream_editor_plugin.cpp delete mode 100644 editor/plugins/audio_stream_editor_plugin.h (limited to 'editor/plugins') diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp deleted file mode 100644 index 9b874ada45..0000000000 --- a/editor/plugins/audio_stream_editor_plugin.cpp +++ /dev/null @@ -1,285 +0,0 @@ -/*************************************************************************/ -/* audio_stream_editor_plugin.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#include "audio_stream_editor_plugin.h" - -#include "core/config/project_settings.h" -#include "core/io/resource_loader.h" -#include "core/os/keyboard.h" -#include "editor/audio_stream_preview.h" -#include "editor/editor_node.h" -#include "editor/editor_scale.h" -#include "editor/editor_settings.h" - -void AudioStreamEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: { - AudioStreamPreviewGenerator::get_singleton()->connect("preview_updated", callable_mp(this, &AudioStreamEditor::_preview_changed)); - } break; - - case NOTIFICATION_THEME_CHANGED: - case NOTIFICATION_ENTER_TREE: { - _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); - _stop_button->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"))); - _preview->set_color(get_theme_color(SNAME("dark_color_2"), SNAME("Editor"))); - set_color(get_theme_color(SNAME("dark_color_1"), SNAME("Editor"))); - - _indicator->update(); - _preview->update(); - } break; - - case NOTIFICATION_PROCESS: { - _current = _player->get_playback_position(); - _indicator->update(); - } break; - - case NOTIFICATION_VISIBILITY_CHANGED: { - if (!is_visible_in_tree()) { - _stop(); - } - } break; - } -} - -void AudioStreamEditor::_draw_preview() { - Rect2 rect = _preview->get_rect(); - Size2 size = get_size(); - - Ref preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream); - float preview_len = preview->get_length(); - - Vector lines; - lines.resize(size.width * 2); - - for (int i = 0; i < size.width; i++) { - float ofs = i * preview_len / size.width; - float ofs_n = (i + 1) * preview_len / size.width; - float max = preview->get_max(ofs, ofs_n) * 0.5 + 0.5; - float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5; - - int idx = i; - lines.write[idx * 2 + 0] = Vector2(i + 1, rect.position.y + min * rect.size.y); - lines.write[idx * 2 + 1] = Vector2(i + 1, rect.position.y + max * rect.size.y); - } - - Vector color; - color.push_back(get_theme_color(SNAME("contrast_color_2"), SNAME("Editor"))); - - RS::get_singleton()->canvas_item_add_multiline(_preview->get_canvas_item(), lines, color); -} - -void AudioStreamEditor::_preview_changed(ObjectID p_which) { - if (stream.is_valid() && stream->get_instance_id() == p_which) { - _preview->update(); - } -} - -void AudioStreamEditor::_audio_changed() { - if (!is_visible()) { - return; - } - update(); -} - -void AudioStreamEditor::_play() { - if (_player->is_playing()) { - // '_pausing' variable indicates that we want to pause the audio player, not stop it. See '_on_finished()'. - _pausing = true; - _player->stop(); - _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); - set_process(false); - } else { - _player->play(_current); - _play_button->set_icon(get_theme_icon(SNAME("Pause"), SNAME("EditorIcons"))); - set_process(true); - } -} - -void AudioStreamEditor::_stop() { - _player->stop(); - _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); - _current = 0; - _indicator->update(); - set_process(false); -} - -void AudioStreamEditor::_on_finished() { - _play_button->set_icon(get_theme_icon(SNAME("MainPlay"), SNAME("EditorIcons"))); - if (!_pausing) { - _current = 0; - _indicator->update(); - } else { - _pausing = false; - } - set_process(false); -} - -void AudioStreamEditor::_draw_indicator() { - if (!stream.is_valid()) { - return; - } - - Rect2 rect = _preview->get_rect(); - float len = stream->get_length(); - float ofs_x = _current / len * rect.size.width; - const Color color = get_theme_color(SNAME("accent_color"), SNAME("Editor")); - _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), color, Math::round(2 * EDSCALE)); - _indicator->draw_texture( - get_theme_icon(SNAME("TimelineIndicator"), SNAME("EditorIcons")), - Point2(ofs_x - get_theme_icon(SNAME("TimelineIndicator"), SNAME("EditorIcons"))->get_width() * 0.5, 0), - color); - - _current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /"); -} - -void AudioStreamEditor::_on_input_indicator(Ref p_event) { - const Ref mb = p_event; - if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) { - if (mb->is_pressed()) { - _seek_to(mb->get_position().x); - } - _dragging = mb->is_pressed(); - } - - const Ref mm = p_event; - if (mm.is_valid()) { - if (_dragging) { - _seek_to(mm->get_position().x); - } - } -} - -void AudioStreamEditor::_seek_to(real_t p_x) { - _current = p_x / _preview->get_rect().size.x * stream->get_length(); - _current = CLAMP(_current, 0, stream->get_length()); - _player->seek(_current); - _indicator->update(); -} - -void AudioStreamEditor::edit(Ref p_stream) { - if (!stream.is_null()) { - stream->disconnect("changed", callable_mp(this, &AudioStreamEditor::_audio_changed)); - } - - stream = p_stream; - _player->set_stream(stream); - _current = 0; - String text = String::num(stream->get_length(), 2).pad_decimals(2) + "s"; - _duration_label->set_text(text); - - if (!stream.is_null()) { - stream->connect("changed", callable_mp(this, &AudioStreamEditor::_audio_changed)); - update(); - } else { - hide(); - } -} - -void AudioStreamEditor::_bind_methods() { -} - -AudioStreamEditor::AudioStreamEditor() { - set_custom_minimum_size(Size2(1, 100) * EDSCALE); - - _player = memnew(AudioStreamPlayer); - _player->connect("finished", callable_mp(this, &AudioStreamEditor::_on_finished)); - add_child(_player); - - VBoxContainer *vbox = memnew(VBoxContainer); - vbox->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_MINSIZE, 0); - add_child(vbox); - - _preview = memnew(ColorRect); - _preview->set_v_size_flags(SIZE_EXPAND_FILL); - _preview->connect("draw", callable_mp(this, &AudioStreamEditor::_draw_preview)); - vbox->add_child(_preview); - - _indicator = memnew(Control); - _indicator->set_anchors_and_offsets_preset(PRESET_FULL_RECT); - _indicator->connect("draw", callable_mp(this, &AudioStreamEditor::_draw_indicator)); - _indicator->connect("gui_input", callable_mp(this, &AudioStreamEditor::_on_input_indicator)); - _preview->add_child(_indicator); - - HBoxContainer *hbox = memnew(HBoxContainer); - hbox->add_theme_constant_override("separation", 0); - vbox->add_child(hbox); - - _play_button = memnew(Button); - _play_button->set_flat(true); - hbox->add_child(_play_button); - _play_button->set_focus_mode(Control::FOCUS_NONE); - _play_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_play)); - _play_button->set_shortcut(ED_SHORTCUT("inspector/audio_preview_play_pause", TTR("Audio Preview Play/Pause"), Key::SPACE)); - - _stop_button = memnew(Button); - _stop_button->set_flat(true); - hbox->add_child(_stop_button); - _stop_button->set_focus_mode(Control::FOCUS_NONE); - _stop_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_stop)); - - _current_label = memnew(Label); - _current_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); - _current_label->set_h_size_flags(SIZE_EXPAND_FILL); - _current_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("status_source"), SNAME("EditorFonts"))); - _current_label->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("status_source_size"), SNAME("EditorFonts"))); - _current_label->set_modulate(Color(1, 1, 1, 0.5)); - hbox->add_child(_current_label); - - _duration_label = memnew(Label); - _duration_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("status_source"), SNAME("EditorFonts"))); - _duration_label->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("status_source_size"), SNAME("EditorFonts"))); - hbox->add_child(_duration_label); -} - -void AudioStreamEditorPlugin::edit(Object *p_object) { - AudioStream *s = Object::cast_to(p_object); - if (!s) { - return; - } - - audio_editor->edit(Ref(s)); -} - -bool AudioStreamEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("AudioStream"); -} - -void AudioStreamEditorPlugin::make_visible(bool p_visible) { - audio_editor->set_visible(p_visible); -} - -AudioStreamEditorPlugin::AudioStreamEditorPlugin() { - audio_editor = memnew(AudioStreamEditor); - add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, audio_editor); - audio_editor->hide(); -} - -AudioStreamEditorPlugin::~AudioStreamEditorPlugin() { -} diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h deleted file mode 100644 index 0d927bddd5..0000000000 --- a/editor/plugins/audio_stream_editor_plugin.h +++ /dev/null @@ -1,91 +0,0 @@ -/*************************************************************************/ -/* audio_stream_editor_plugin.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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_EDITOR_PLUGIN_H -#define AUDIO_STREAM_EDITOR_PLUGIN_H - -#include "editor/editor_plugin.h" -#include "scene/audio/audio_stream_player.h" -#include "scene/gui/color_rect.h" -#include "scene/resources/texture.h" - -class AudioStreamEditor : public ColorRect { - GDCLASS(AudioStreamEditor, ColorRect); - - Ref stream; - AudioStreamPlayer *_player = nullptr; - ColorRect *_preview = nullptr; - Control *_indicator = nullptr; - Label *_current_label = nullptr; - Label *_duration_label = nullptr; - - Button *_play_button = nullptr; - Button *_stop_button = nullptr; - - float _current = 0; - bool _dragging = false; - bool _pausing = false; - - void _audio_changed(); - -protected: - void _notification(int p_what); - void _preview_changed(ObjectID p_which); - void _play(); - void _stop(); - void _on_finished(); - void _draw_preview(); - void _draw_indicator(); - void _on_input_indicator(Ref p_event); - void _seek_to(real_t p_x); - static void _bind_methods(); - -public: - void edit(Ref p_stream); - AudioStreamEditor(); -}; - -class AudioStreamEditorPlugin : public EditorPlugin { - GDCLASS(AudioStreamEditorPlugin, EditorPlugin); - - AudioStreamEditor *audio_editor = nullptr; - -public: - virtual String get_name() const override { return "Audio"; } - bool has_main_screen() const override { return false; } - virtual void edit(Object *p_object) override; - virtual bool handles(Object *p_object) const override; - virtual void make_visible(bool p_visible) override; - - AudioStreamEditorPlugin(); - ~AudioStreamEditorPlugin(); -}; - -#endif // AUDIO_STREAM_EDITOR_PLUGIN_H diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 478f4264e5..6b632101d3 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -599,7 +599,7 @@ Ref EditorAudioStreamPreviewPlugin::generate(const Ref &p_f uint8_t *imgdata = img.ptrw(); uint8_t *imgw = imgdata; - Ref playback = stream->instance_playback(); + Ref playback = stream->instantiate_playback(); ERR_FAIL_COND_V(playback.is_null(), Ref()); real_t len_s = stream->get_length(); -- cgit v1.2.3