diff options
-rw-r--r-- | core/ustring.cpp | 3 | ||||
-rw-r--r-- | core/ustring.h | 2 | ||||
-rw-r--r-- | core/variant_call.cpp | 6 | ||||
-rw-r--r-- | doc/classes/ColorPicker.xml | 5 | ||||
-rw-r--r-- | doc/classes/String.xml | 4 | ||||
-rw-r--r-- | editor/code_editor.cpp | 24 | ||||
-rw-r--r-- | editor/code_editor.h | 1 | ||||
-rw-r--r-- | editor/script_editor_debugger.cpp | 20 | ||||
-rw-r--r-- | modules/cvtt/image_compress_cvtt.cpp | 6 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.cpp | 62 | ||||
-rw-r--r-- | scene/gui/color_picker.cpp | 128 | ||||
-rw-r--r-- | scene/gui/color_picker.h | 11 | ||||
-rw-r--r-- | servers/audio/effects/audio_effect_pitch_shift.cpp | 42 | ||||
-rw-r--r-- | servers/audio/effects/audio_effect_pitch_shift.h | 22 | ||||
-rw-r--r-- | servers/audio/effects/audio_effect_spectrum_analyzer.cpp | 5 |
15 files changed, 266 insertions, 75 deletions
diff --git a/core/ustring.cpp b/core/ustring.cpp index 35b817b1d2..686aa6f8e3 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -2331,6 +2331,9 @@ String String::insert(int p_at_pos, const String &p_string) const { } String String::substr(int p_from, int p_chars) const { + if (p_chars == -1) + p_chars = length() - p_from; + if (empty() || p_from < 0 || p_from >= length() || p_chars <= 0) return ""; diff --git a/core/ustring.h b/core/ustring.h index 5b9be9f27c..ecf934a26b 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -201,7 +201,7 @@ public: } /* complex helpers */ - String substr(int p_from, int p_chars) const; + String substr(int p_from, int p_chars = -1) const; int find(const String &p_str, int p_from = 0) const; ///< return <0 if failed int find(const char *p_str, int p_from = 0) const; ///< return <0 if failed int find_char(const CharType &p_char, int p_from = 0) const; ///< return <0 if failed diff --git a/core/variant_call.cpp b/core/variant_call.cpp index b3a4a13b08..dc28f1ca02 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -285,6 +285,8 @@ struct _VariantCall { VCALL_LOCALMEM0R(String, get_file); VCALL_LOCALMEM0R(String, xml_escape); VCALL_LOCALMEM0R(String, xml_unescape); + VCALL_LOCALMEM0R(String, http_escape); + VCALL_LOCALMEM0R(String, http_unescape); VCALL_LOCALMEM0R(String, c_escape); VCALL_LOCALMEM0R(String, c_unescape); VCALL_LOCALMEM0R(String, json_escape); @@ -1497,7 +1499,7 @@ void register_variant_methods() { ADDFUNC1R(STRING, INT, String, casecmp_to, STRING, "to", varray()); ADDFUNC1R(STRING, INT, String, nocasecmp_to, STRING, "to", varray()); ADDFUNC0R(STRING, INT, String, length, varray()); - ADDFUNC2R(STRING, STRING, String, substr, INT, "from", INT, "len", varray()); + ADDFUNC2R(STRING, STRING, String, substr, INT, "from", INT, "len", varray(-1)); ADDFUNC2R(STRING, INT, String, find, STRING, "what", INT, "from", varray(0)); @@ -1550,6 +1552,8 @@ void register_variant_methods() { ADDFUNC0R(STRING, STRING, String, get_file, varray()); ADDFUNC0R(STRING, STRING, String, xml_escape, varray()); ADDFUNC0R(STRING, STRING, String, xml_unescape, varray()); + ADDFUNC0R(STRING, STRING, String, http_escape, varray()); + ADDFUNC0R(STRING, STRING, String, http_unescape, varray()); ADDFUNC0R(STRING, STRING, String, c_escape, varray()); ADDFUNC0R(STRING, STRING, String, c_unescape, varray()); ADDFUNC0R(STRING, STRING, String, json_escape, varray()); diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index 32e6014c75..1fefc719b7 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -49,8 +49,13 @@ </member> <member name="presets_visible" type="bool" setter="set_presets_visible" getter="are_presets_visible"> </member> + <member name="hsv_mode" type="bool" setter="set_hsv_mode" getter="is_hsv_mode"> + If [code]true[/code], allows to edit color with Hue/Saturation/Value sliders. + [b]Note:[/b] Cannot be enabled if raw mode is on. + </member> <member name="raw_mode" type="bool" setter="set_raw_mode" getter="is_raw_mode"> If [code]true[/code], allows the color R, G, B component values to go beyond 1.0, which can be used for certain special operations that require it (like tinting without darkening or rendering sprites in HDR). + [b]Note:[/b] Cannot be enabled if hsv mode is on. </member> </members> <signals> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index af7e5a395a..ff0572f384 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -757,10 +757,10 @@ </return> <argument index="0" name="from" type="int"> </argument> - <argument index="1" name="len" type="int"> + <argument index="1" name="len" type="int" default="-1"> </argument> <description> - Returns part of the string from the position [code]from[/code] with length [code]len[/code]. + Returns part of the string from the position [code]from[/code] with length [code]len[/code]. Argument [code]len[/code] is optional and using -1 will return remaining characters from given position. </description> </method> <method name="to_ascii"> diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index e471993fc7..8b3c537fe3 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -587,6 +587,26 @@ FindReplaceBar::FindReplaceBar() { /*** CODE EDITOR ****/ +// This function should be used to handle shortcuts that could otherwise +// be handled too late if they weren't handled here. +void CodeTextEditor::_input(const Ref<InputEvent> &event) { + + const Ref<InputEventKey> key_event = event; + if (!key_event.is_valid() || !key_event->is_pressed()) + return; + + if (ED_IS_SHORTCUT("script_text_editor/move_up", key_event)) { + move_lines_up(); + accept_event(); + return; + } + if (ED_IS_SHORTCUT("script_text_editor/move_down", key_event)) { + move_lines_down(); + accept_event(); + return; + } +} + void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; @@ -1375,6 +1395,9 @@ void CodeTextEditor::_notification(int p_what) { warning_button->set_icon(get_icon("NodeWarning", "EditorIcons")); add_constant_override("separation", 4 * EDSCALE); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + set_process_input(is_visible_in_tree()); + } break; default: break; } @@ -1454,6 +1477,7 @@ void CodeTextEditor::remove_all_bookmarks() { void CodeTextEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("_input"), &CodeTextEditor::_input); ClassDB::bind_method("_text_editor_gui_input", &CodeTextEditor::_text_editor_gui_input); ClassDB::bind_method("_line_col_changed", &CodeTextEditor::_line_col_changed); ClassDB::bind_method("_text_changed", &CodeTextEditor::_text_changed); diff --git a/editor/code_editor.h b/editor/code_editor.h index 0ef8ec7061..ce219f340c 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -165,6 +165,7 @@ class CodeTextEditor : public VBoxContainer { void _font_resize_timeout(); bool _add_font_size(int p_delta); + void _input(const Ref<InputEvent> &event); void _text_editor_gui_input(const Ref<InputEvent> &p_event); void _zoom_in(); void _zoom_out(); diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 3b086c6316..3167abb745 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -1121,10 +1121,13 @@ void ScriptEditorDebugger::_notification(int p_what) { last_warning_count = warning_count; } - if (connection.is_null()) { - - if (server->is_connection_available()) { - + if (server->is_connection_available()) { + if (connection.is_valid()) { + // We already have a valid connection. Disconnecting any new connecting client to prevent it from hanging. + // (If we don't keep a reference to the connection it will be destroyed and disconnect_from_host will be called internally) + server->take_connection(); + } else { + // We just got the first connection. connection = server->take_connection(); if (connection.is_null()) break; @@ -1158,12 +1161,11 @@ void ScriptEditorDebugger::_notification(int p_what) { if (profiler->is_profiling()) { _profiler_activate(true); } - - } else { - - break; } - }; + } + + if (connection.is_null()) + break; if (!connection->is_connected_to_host()) { stop(); diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index 0a70ff535f..024e9ffc3b 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -145,7 +145,7 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressS int h = p_image->get_height(); bool is_ldr = (p_image->get_format() <= Image::FORMAT_RGBA8); - bool is_hdr = (p_image->get_format() == Image::FORMAT_RGBH); + bool is_hdr = (p_image->get_format() >= Image::FORMAT_RH) && (p_image->get_format() <= Image::FORMAT_RGBE9995); if (!is_ldr && !is_hdr) { return; // Not a usable source format @@ -175,6 +175,10 @@ void image_compress_cvtt(Image *p_image, float p_lossy_quality, Image::CompressS bool is_signed = false; if (is_hdr) { + if (p_image->get_format() != Image::FORMAT_RGBH) { + p_image->convert(Image::FORMAT_RGBH); + } + PoolVector<uint8_t>::Read rb = p_image->get_data().read(); const uint16_t *source_data = reinterpret_cast<const uint16_t *>(&rb[0]); diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index cff9ba55b8..bae5eca218 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -133,35 +133,13 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta return NULL; } -String GDScriptFunction::_get_call_error(const Variant::CallError &p_err, const String &p_where, const Variant **argptrs) const { - - String err_text; - - if (p_err.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { - int errorarg = p_err.argument; - err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(p_err.expected) + "."; - } else if (p_err.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { - err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments."; - } else if (p_err.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { - err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments."; - } else if (p_err.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) { - err_text = "Invalid call. Nonexistent " + p_where + "."; - } else if (p_err.error == Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) { - err_text = "Attempt to call " + p_where + " on a null instance."; - } else { - err_text = "Bug, call error: #" + itos(p_err.error); - } - - return err_text; -} - #ifdef DEBUG_ENABLED -static String _get_var_type(const Variant *p_type) { +static String _get_var_type(const Variant *p_var) { String basestr; - if (p_type->get_type() == Variant::OBJECT) { - Object *bobj = *p_type; + if (p_var->get_type() == Variant::OBJECT) { + Object *bobj = *p_var; if (!bobj) { basestr = "null instance"; } else { @@ -176,12 +154,42 @@ static String _get_var_type(const Variant *p_type) { } } else { - basestr = Variant::get_type_name(p_type->get_type()); + basestr = Variant::get_type_name(p_var->get_type()); } return basestr; } -#endif +#endif // DEBUG_ENABLED + +String GDScriptFunction::_get_call_error(const Variant::CallError &p_err, const String &p_where, const Variant **argptrs) const { + + String err_text; + + if (p_err.error == Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { + int errorarg = p_err.argument; + // Handle the Object to Object case separately as we don't have further class details. +#ifdef DEBUG_ENABLED + if (p_err.expected == Variant::OBJECT && argptrs[errorarg]->get_type() == p_err.expected) { + err_text = "Invalid type in " + p_where + ". The Object-derived class of argument " + itos(errorarg + 1) + " (" + _get_var_type(argptrs[errorarg]) + ") is not a subclass of the expected argument class."; + } else +#endif // DEBUG_ENABLED + { + err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(p_err.expected) + "."; + } + } else if (p_err.error == Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { + err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments."; + } else if (p_err.error == Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { + err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments."; + } else if (p_err.error == Variant::CallError::CALL_ERROR_INVALID_METHOD) { + err_text = "Invalid call. Nonexistent " + p_where + "."; + } else if (p_err.error == Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) { + err_text = "Attempt to call " + p_where + " on a null instance."; + } else { + err_text = "Bug, call error: #" + itos(p_err.error); + } + + return err_text; +} #if defined(__GNUC__) #define OPCODES_TABLE \ diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index bca3471091..b6abfdd6a8 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -93,6 +93,28 @@ void ColorPicker::set_focus_on_line_edit() { void ColorPicker::_update_controls() { + const char *rgb[3] = { "R", "G", "B" }; + const char *hsv[3] = { "H", "S", "V" }; + + if (hsv_mode_enabled) { + for (int i = 0; i < 3; i++) + labels[i]->set_text(hsv[i]); + } else { + for (int i = 0; i < 3; i++) + labels[i]->set_text(rgb[i]); + } + + if (hsv_mode_enabled) { + set_raw_mode(false); + btn_raw->set_disabled(true); + } else if (raw_mode_enabled) { + set_hsv_mode(false); + btn_hsv->set_disabled(true); + } else { + btn_raw->set_disabled(false); + btn_hsv->set_disabled(false); + } + if (edit_alpha) { values[3]->show(); scroll[3]->show(); @@ -104,7 +126,7 @@ void ColorPicker::_update_controls() { } } -void ColorPicker::set_pick_color(const Color &p_color) { +void ColorPicker::set_pick_color(const Color &p_color, bool p_update_sliders) { color = p_color; if (color != last_hsv) { @@ -117,7 +139,7 @@ void ColorPicker::set_pick_color(const Color &p_color) { if (!is_inside_tree()) return; - _update_color(); + _update_color(p_update_sliders); } void ColorPicker::set_edit_alpha(bool p_show) { @@ -142,11 +164,18 @@ void ColorPicker::_value_changed(double) { if (updating) return; - for (int i = 0; i < 4; i++) { - color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0); + if (hsv_mode_enabled) { + color.set_hsv(scroll[0]->get_value() / 360.0, + scroll[1]->get_value() / 100.0, + scroll[2]->get_value() / 100.0, + scroll[3]->get_value() / 100.0); + } else { + for (int i = 0; i < 4; i++) { + color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0); + } } - set_pick_color(color); + set_pick_color(color, false); emit_signal("color_changed", color); } @@ -167,22 +196,40 @@ void ColorPicker::_html_entered(const String &p_html) { emit_signal("color_changed", color); } -void ColorPicker::_update_color() { +void ColorPicker::_update_color(bool p_update_sliders) { updating = true; - for (int i = 0; i < 4; i++) { - if (raw_mode_enabled) { - scroll[i]->set_step(0.01); - scroll[i]->set_max(100); - if (i == 3) - scroll[i]->set_max(1); - scroll[i]->set_value(color.components[i]); + if (p_update_sliders) { + + if (hsv_mode_enabled) { + for (int i = 0; i < 4; i++) { + scroll[i]->set_step(0.1); + } + + scroll[0]->set_max(360); + scroll[0]->set_value(h * 360.0); + scroll[1]->set_max(100); + scroll[1]->set_value(s * 100.0); + scroll[2]->set_max(100); + scroll[2]->set_value(v * 100.0); + scroll[3]->set_max(100); + scroll[3]->set_value(color.components[3] * 100.0); } else { - scroll[i]->set_step(1); - const float byte_value = color.components[i] * 255.0; - scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1); - scroll[i]->set_value(byte_value); + for (int i = 0; i < 4; i++) { + if (raw_mode_enabled) { + scroll[i]->set_step(0.01); + scroll[i]->set_max(100); + if (i == 3) + scroll[i]->set_max(1); + scroll[i]->set_value(color.components[i]); + } else { + scroll[i]->set_step(1); + const float byte_value = color.components[i] * 255.0; + scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1); + scroll[i]->set_value(byte_value); + } + } } } @@ -272,13 +319,33 @@ PoolColorArray ColorPicker::get_presets() const { return arr; } +void ColorPicker::set_hsv_mode(bool p_enabled) { + + if (hsv_mode_enabled == p_enabled || raw_mode_enabled) + return; + hsv_mode_enabled = p_enabled; + if (btn_hsv->is_pressed() != p_enabled) + btn_hsv->set_pressed(p_enabled); + + if (!is_inside_tree()) + return; + + _update_controls(); + _update_color(); +} + +bool ColorPicker::is_hsv_mode() const { + + return hsv_mode_enabled; +} + void ColorPicker::set_raw_mode(bool p_enabled) { - if (raw_mode_enabled == p_enabled) + if (raw_mode_enabled == p_enabled || hsv_mode_enabled) return; raw_mode_enabled = p_enabled; - if (btn_mode->is_pressed() != p_enabled) - btn_mode->set_pressed(p_enabled); + if (btn_raw->is_pressed() != p_enabled) + btn_raw->set_pressed(p_enabled); if (!is_inside_tree()) return; @@ -592,6 +659,8 @@ void ColorPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPicker::set_pick_color); ClassDB::bind_method(D_METHOD("get_pick_color"), &ColorPicker::get_pick_color); + ClassDB::bind_method(D_METHOD("set_hsv_mode", "mode"), &ColorPicker::set_hsv_mode); + ClassDB::bind_method(D_METHOD("is_hsv_mode"), &ColorPicker::is_hsv_mode); ClassDB::bind_method(D_METHOD("set_raw_mode", "mode"), &ColorPicker::set_raw_mode); ClassDB::bind_method(D_METHOD("is_raw_mode"), &ColorPicker::is_raw_mode); ClassDB::bind_method(D_METHOD("set_deferred_mode", "mode"), &ColorPicker::set_deferred_mode); @@ -623,6 +692,7 @@ void ColorPicker::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hsv_mode"), "set_hsv_mode", "is_hsv_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deferred_mode"), "set_deferred_mode", "is_deferred_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "presets_enabled"), "set_presets_enabled", "are_presets_enabled"); @@ -639,6 +709,7 @@ ColorPicker::ColorPicker() : updating = true; edit_alpha = true; text_is_constructor = false; + hsv_mode_enabled = false; raw_mode_enabled = false; deferred_mode_enabled = false; changing_color = false; @@ -689,13 +760,12 @@ ColorPicker::ColorPicker() : VBoxContainer *vbr = memnew(VBoxContainer); add_child(vbr); vbr->set_h_size_flags(SIZE_EXPAND_FILL); - const char *lt[4] = { "R", "G", "B", "A" }; for (int i = 0; i < 4; i++) { HBoxContainer *hbc = memnew(HBoxContainer); - labels[i] = memnew(Label(lt[i])); + labels[i] = memnew(Label()); labels[i]->set_custom_minimum_size(Size2(get_constant("label_width"), 0)); labels[i]->set_v_size_flags(SIZE_SHRINK_CENTER); hbc->add_child(labels[i]); @@ -719,14 +789,20 @@ ColorPicker::ColorPicker() : vbr->add_child(hbc); } + labels[3]->set_text("A"); HBoxContainer *hhb = memnew(HBoxContainer); vbr->add_child(hhb); - btn_mode = memnew(CheckButton); - hhb->add_child(btn_mode); - btn_mode->set_text(TTR("Raw Mode")); - btn_mode->connect("toggled", this, "set_raw_mode"); + btn_hsv = memnew(CheckButton); + hhb->add_child(btn_hsv); + btn_hsv->set_text(TTR("HSV")); + btn_hsv->connect("toggled", this, "set_hsv_mode"); + + btn_raw = memnew(CheckButton); + hhb->add_child(btn_raw); + btn_raw->set_text(TTR("Raw")); + btn_raw->connect("toggled", this, "set_raw_mode"); text_type = memnew(Button); hhb->add_child(text_type); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index b5ddf2d0c2..94640be4f0 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -58,7 +58,8 @@ private: Button *bt_add_preset; List<Color> presets; ToolButton *btn_pick; - CheckButton *btn_mode; + CheckButton *btn_hsv; + CheckButton *btn_raw; HSlider *scroll[4]; SpinBox *values[4]; Label *labels[4]; @@ -70,6 +71,7 @@ private: Color color; bool raw_mode_enabled; + bool hsv_mode_enabled; bool deferred_mode_enabled; bool updating; bool changing_color; @@ -81,7 +83,7 @@ private: void _html_entered(const String &p_html); void _value_changed(double); void _update_controls(); - void _update_color(); + void _update_color(bool p_update_sliders = true); void _update_presets(); void _update_text_value(); void _text_type_toggled(); @@ -106,13 +108,16 @@ public: void set_edit_alpha(bool p_show); bool is_editing_alpha() const; - void set_pick_color(const Color &p_color); + void set_pick_color(const Color &p_color, bool p_update_sliders = true); Color get_pick_color() const; void add_preset(const Color &p_color); void erase_preset(const Color &p_color); PoolColorArray get_presets() const; + void set_hsv_mode(bool p_enabled); + bool is_hsv_mode() const; + void set_raw_mode(bool p_enabled); bool is_raw_mode() const; diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp index ca2a88f858..c250f2e2bd 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.cpp +++ b/servers/audio/effects/audio_effect_pitch_shift.cpp @@ -293,14 +293,16 @@ void AudioEffectPitchShiftInstance::process(const AudioFrame *p_src_frames, Audi float *out_l = (float *)p_dst_frames; float *out_r = out_l + 1; - shift_l.PitchShift(base->pitch_scale, p_frame_count, 2048, 4, sample_rate, in_l, out_l, 2); - shift_r.PitchShift(base->pitch_scale, p_frame_count, 2048, 4, sample_rate, in_r, out_r, 2); + shift_l.PitchShift(base->pitch_scale, p_frame_count, fft_size, base->oversampling, sample_rate, in_l, out_l, 2); + shift_r.PitchShift(base->pitch_scale, p_frame_count, fft_size, base->oversampling, sample_rate, in_r, out_r, 2); } Ref<AudioEffectInstance> AudioEffectPitchShift::instance() { Ref<AudioEffectPitchShiftInstance> ins; ins.instance(); ins->base = Ref<AudioEffectPitchShift>(this); + static const int fft_sizes[FFT_SIZE_MAX] = { 256, 512, 1024, 2048, 4096 }; + ins->fft_size = fft_sizes[fft_size]; return ins; } @@ -315,14 +317,50 @@ float AudioEffectPitchShift::get_pitch_scale() const { return pitch_scale; } +void AudioEffectPitchShift::set_oversampling(int p_oversampling) { + ERR_FAIL_COND(p_oversampling < 4); + oversampling = p_oversampling; +} + +int AudioEffectPitchShift::get_oversampling() const { + + return oversampling; +} + +void AudioEffectPitchShift::set_fft_size(FFT_Size p_fft_size) { + ERR_FAIL_INDEX(p_fft_size, FFT_SIZE_MAX); + fft_size = p_fft_size; +} + +AudioEffectPitchShift::FFT_Size AudioEffectPitchShift::get_fft_size() const { + return fft_size; +} + void AudioEffectPitchShift::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pitch_scale", "rate"), &AudioEffectPitchShift::set_pitch_scale); ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioEffectPitchShift::get_pitch_scale); + ClassDB::bind_method(D_METHOD("set_oversampling", "amount"), &AudioEffectPitchShift::set_oversampling); + ClassDB::bind_method(D_METHOD("get_oversampling"), &AudioEffectPitchShift::get_oversampling); + + ClassDB::bind_method(D_METHOD("set_fft_size", "size"), &AudioEffectPitchShift::set_fft_size); + ClassDB::bind_method(D_METHOD("get_fft_size"), &AudioEffectPitchShift::get_fft_size); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_pitch_scale", "get_pitch_scale"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "oversampling", PROPERTY_HINT_RANGE, "4,32,1"), "set_oversampling", "get_oversampling"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fft_size", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096"), "set_fft_size", "get_fft_size"); + + BIND_ENUM_CONSTANT(FFT_SIZE_256); + BIND_ENUM_CONSTANT(FFT_SIZE_512); + BIND_ENUM_CONSTANT(FFT_SIZE_1024); + BIND_ENUM_CONSTANT(FFT_SIZE_2048); + BIND_ENUM_CONSTANT(FFT_SIZE_4096); + BIND_ENUM_CONSTANT(FFT_SIZE_MAX); } AudioEffectPitchShift::AudioEffectPitchShift() { pitch_scale = 1.0; + oversampling = 4; + fft_size = FFT_SIZE_2048; } diff --git a/servers/audio/effects/audio_effect_pitch_shift.h b/servers/audio/effects/audio_effect_pitch_shift.h index febc20e9d5..0c80cb6344 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.h +++ b/servers/audio/effects/audio_effect_pitch_shift.h @@ -76,6 +76,7 @@ class AudioEffectPitchShiftInstance : public AudioEffectInstance { friend class AudioEffectPitchShift; Ref<AudioEffectPitchShift> base; + int fft_size; SMBPitchShift shift_l; SMBPitchShift shift_r; @@ -85,11 +86,22 @@ public: class AudioEffectPitchShift : public AudioEffect { GDCLASS(AudioEffectPitchShift, AudioEffect) +public: + enum FFT_Size { + FFT_SIZE_256, + FFT_SIZE_512, + FFT_SIZE_1024, + FFT_SIZE_2048, + FFT_SIZE_4096, + FFT_SIZE_MAX + }; +public: friend class AudioEffectPitchShiftInstance; float pitch_scale; - int window_size; + int oversampling; + FFT_Size fft_size; float wet; float dry; bool filter; @@ -103,7 +115,15 @@ public: void set_pitch_scale(float p_pitch_scale); float get_pitch_scale() const; + void set_oversampling(int p_oversampling); + int get_oversampling() const; + + void set_fft_size(FFT_Size); + FFT_Size get_fft_size() const; + AudioEffectPitchShift(); }; +VARIANT_ENUM_CAST(AudioEffectPitchShift::FFT_Size); + #endif // AUDIO_EFFECT_PITCH_SHIFT_H diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp index f5ac0afefa..305f9046c3 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp @@ -111,9 +111,10 @@ void AudioEffectSpectrumAnalyzerInstance::process(const AudioFrame *p_src_frames float *fftw = temporal_fft.ptrw(); for (int i = 0; i < to_fill; i++) { //left and right buffers - fftw[(i + temporal_fft_pos) * 2] = p_src_frames[i].l; + float window = -0.5 * Math::cos(2.0 * Math_PI * (double)i / (double)to_fill) + 0.5; + fftw[(i + temporal_fft_pos) * 2] = window * p_src_frames[i].l; fftw[(i + temporal_fft_pos) * 2 + 1] = 0; - fftw[(i + temporal_fft_pos + fft_size * 2) * 2] = p_src_frames[i].r; + fftw[(i + temporal_fft_pos + fft_size * 2) * 2] = window * p_src_frames[i].r; fftw[(i + temporal_fft_pos + fft_size * 2) * 2 + 1] = 0; } |