From b389ce5ccd664c993772a0b71ba99a875106b523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= Date: Tue, 15 Mar 2022 16:09:39 +0100 Subject: [PATCH] ResourceImporterWAV: Allow configuring loop mode on import The new `edit/loop_mode` import options lets user choose to either: - Detect loop points from the WAV (default, same behavior as before) - Set the loop mode and loop points manually like in AudioStreamSample Fixes #46164. --- editor/import/resource_importer_wav.cpp | 49 +++++++++++++++++-------- scene/resources/audio_stream_sample.h | 1 + 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index 8cb9a47fb52..68d1d23dd86 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -63,6 +63,11 @@ bool ResourceImporterWAV::get_option_visibility(const String &p_path, const Stri return false; } + // Don't show begin/end loop points if loop mode is auto-detected or disabled. + if ((int)p_options["edit/loop_mode"] < 2 && (p_option == "edit/loop_begin" || p_option == "edit/loop_end")) { + return false; + } + return true; } @@ -81,7 +86,10 @@ void ResourceImporterWAV::get_import_options(const String &p_path, Listpush_back(ImportOption(PropertyInfo(Variant::FLOAT, "force/max_rate_hz", PROPERTY_HINT_RANGE, "11025,192000,1,exp"), 44100)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/trim"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/normalize"), false)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/loop"), false)); + // Keep the `edit/loop_mode` enum in sync with AudioStreamSample::LoopMode (note: +1 offset due to "Detect From WAV"). + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "edit/loop_mode", PROPERTY_HINT_ENUM, "Detect From WAV,Disabled,Forward,Ping-Pong,Backward", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "edit/loop_begin"), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "edit/loop_end"), -1)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Disabled,RAM (Ima-ADPCM)"), 0)); } @@ -119,10 +127,14 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Not a WAV file (no WAVE RIFF header)."); } + // Let users override potential loop points from the WAV. + // We parse the WAV loop points only with "Detect From WAV" (0). + int import_loop_mode = p_options["edit/loop_mode"]; + int format_bits = 0; int format_channels = 0; - AudioStreamSample::LoopMode loop = AudioStreamSample::LOOP_DISABLED; + AudioStreamSample::LoopMode loop_mode = AudioStreamSample::LOOP_DISABLED; uint16_t compression_code = 1; bool format_found = false; bool data_found = false; @@ -248,8 +260,8 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s } } - if (chunkID[0] == 's' && chunkID[1] == 'm' && chunkID[2] == 'p' && chunkID[3] == 'l') { - //loop point info! + if (import_loop_mode == 0 && chunkID[0] == 's' && chunkID[1] == 'm' && chunkID[2] == 'p' && chunkID[3] == 'l') { + // Loop point info! /** * Consider exploring next document: @@ -270,11 +282,11 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s int loop_type = file->get_32(); if (loop_type == 0x00 || loop_type == 0x01 || loop_type == 0x02) { if (loop_type == 0x00) { - loop = AudioStreamSample::LOOP_FORWARD; + loop_mode = AudioStreamSample::LOOP_FORWARD; } else if (loop_type == 0x01) { - loop = AudioStreamSample::LOOP_PINGPONG; + loop_mode = AudioStreamSample::LOOP_PINGPONG; } else if (loop_type == 0x02) { - loop = AudioStreamSample::LOOP_BACKWARD; + loop_mode = AudioStreamSample::LOOP_BACKWARD; } loop_begin = file->get_32(); loop_end = file->get_32(); @@ -346,7 +358,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s } } - if (loop) { + if (loop_mode) { loop_begin = (int)(loop_begin * (float)new_data_frames / (float)frames); loop_end = (int)(loop_end * (float)new_data_frames / (float)frames); } @@ -377,7 +389,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s bool trim = p_options["edit/trim"]; - if (trim && !loop && format_channels > 0) { + if (trim && (loop_mode != AudioStreamSample::LOOP_DISABLED) && format_channels > 0) { int first = 0; int last = (frames / format_channels) - 1; bool found = false; @@ -421,12 +433,17 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s } } - bool make_loop = p_options["edit/loop"]; - - if (make_loop && !loop) { - loop = AudioStreamSample::LOOP_FORWARD; - loop_begin = 0; - loop_end = frames; + if (import_loop_mode >= 2) { + loop_mode = (AudioStreamSample::LoopMode)(import_loop_mode - 1); + loop_begin = p_options["edit/loop_begin"]; + loop_end = p_options["edit/loop_end"]; + // Wrap around to max frames, so `-1` can be used to select the end, etc. + if (loop_begin < 0) { + loop_begin = CLAMP(loop_begin + frames + 1, 0, frames); + } + if (loop_end < 0) { + loop_end = CLAMP(loop_end + frames + 1, 0, frames); + } } int compression = p_options["compress/mode"]; @@ -512,7 +529,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s sample->set_data(dst_data); sample->set_format(dst_format); sample->set_mix_rate(rate); - sample->set_loop_mode(loop); + sample->set_loop_mode(loop_mode); sample->set_loop_begin(loop_begin); sample->set_loop_end(loop_end); sample->set_stereo(format_channels == 2); diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h index 043a62ff705..357febc27ae 100644 --- a/scene/resources/audio_stream_sample.h +++ b/scene/resources/audio_stream_sample.h @@ -89,6 +89,7 @@ public: FORMAT_IMA_ADPCM }; + // Keep the ResourceImporterWAV `edit/loop_mode` enum hint in sync with these options. enum LoopMode { LOOP_DISABLED, LOOP_FORWARD,