diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e8ff14..0eab05b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added +- Bit depth and sample rate import options. - Paste from JSXFR. ## [1.2.0] - 2022-10-13 diff --git a/README-zh_CN.md b/README-zh_CN.md index c5754d9..200ffec 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -32,6 +32,8 @@ 如果你希望使用原始的 sfxr 保存出的文件,请确保使用 `.sfxr` 扩展名保存。你也可以在原始的 sfxr 中加载并编辑 `.sfxr` 文件。 +`.sfxr` 文件有循环(Loop)、位深度(Bit Depth)、采样率(Sample Rate)等导入选项。可以在 Godot 编辑器的导入面板中找到。 + **注意:** 由于 GDScript 的性能限制,生成较长的音效时编辑器可能会有短暂的停滞。只有编辑器会受此影响。在游戏中使用 `.sfxr` 文件是不会在运行时生成任何东西的。 ## 更新日志 diff --git a/README.md b/README.md index 5d5cccd..24bf453 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,9 @@ But they can be used directly as regular `AudioStream`s. If you want to reuse an existing sound from the original sfxr, make sure to save it with an `.sfxr` extension. You can also load & edit the `.sfxr` file with the original sfxr. +Options for changing Looping, Bit Depth, and Sample Rate are available as import options +of the `.sfxr` file. You can find these options in Godot editor's Import dock. + **Note:** Due to performance constraints with GDScript, the editor may freeze a bit when generating long sounds. This only happens in-editor. Using `.sfxr` files in-game won't generate anything at runtime. diff --git a/addons/gdfxr/SFXRGenerator.gd b/addons/gdfxr/SFXRGenerator.gd index 8e727e8..111edc0 100644 --- a/addons/gdfxr/SFXRGenerator.gd +++ b/addons/gdfxr/SFXRGenerator.gd @@ -5,6 +5,15 @@ const SFXRConfig := preload("SFXRConfig.gd") const master_vol := 0.05 +enum WavBits { + WAV_BITS_8, + WAV_BITS_16, +} +enum WavFreq { + WAV_FREQ_44100, + WAV_FREQ_22050, +} + var _config: SFXRConfig var rep_time: int @@ -41,32 +50,42 @@ var fltdmp: float var fltphp: float -func generate_audio_stream(config: SFXRConfig) -> AudioStreamSample: +func generate_audio_stream( + config: SFXRConfig, + wav_bits: int = WavBits.WAV_BITS_8, + wav_freq: int = WavFreq.WAV_FREQ_44100 +) -> AudioStreamSample: var stream := AudioStreamSample.new() - stream.format = AudioStreamSample.FORMAT_8_BITS - stream.mix_rate = 44100 + stream.format = AudioStreamSample.FORMAT_8_BITS if wav_bits == WavBits.WAV_BITS_8 else AudioStreamSample.FORMAT_16_BITS + stream.mix_rate = 44100 if wav_freq == WavFreq.WAV_FREQ_44100 else 22050 _config = config - stream.data = _generate_samples() + stream.data = _generate_samples(wav_bits, wav_freq).data_array _config = null return stream -func generate_samples(config: SFXRConfig) -> PoolByteArray: +func generate_samples( + config: SFXRConfig, + wav_bits: int = WavBits.WAV_BITS_8, + wav_freq: int = WavFreq.WAV_FREQ_44100 +) -> PoolByteArray: _config = config - var data := _generate_samples() + var data := _generate_samples(wav_bits, wav_freq).data_array _config = null return data -func _generate_samples() -> PoolByteArray: +func _generate_samples(wav_bits: int, wav_freq: int) -> StreamPeerBuffer: _reset_sample(true) var playing_sample := true var env_stage := 0 var env_time := 0 - var output := PoolByteArray([]) + var filesample: float = 0 + var fileacc := 0 + var buffer := StreamPeerBuffer.new() # SynthSample while playing_sample: @@ -174,15 +193,21 @@ func _generate_samples() -> PoolByteArray: ssample *= 4.0 # arbitrary gain to get reasonable output volume... ssample = clamp(ssample, -1.0, +1.0) - var filesample := int((1 + ssample) / 2 * 255) + filesample += ssample + fileacc += 1 - # This is a hack, AudioStreamSample wants a int8_t directly interpreted as uint8_t - filesample += 128 - if filesample > 255: - filesample -= 255 - - output.push_back(filesample) - return output + if wav_freq == WavFreq.WAV_FREQ_44100 or fileacc == 2: + filesample /= fileacc + fileacc = 0 + + if wav_bits == WavBits.WAV_BITS_8: + buffer.put_8(filesample * 255) + else: + buffer.put_16(filesample * 32000) + + filesample = 0 + + return buffer func _reset_sample(restart: bool) -> void: diff --git a/addons/gdfxr/import_plugin.gd b/addons/gdfxr/import_plugin.gd index 2796645..5dce8ff 100644 --- a/addons/gdfxr/import_plugin.gd +++ b/addons/gdfxr/import_plugin.gd @@ -39,6 +39,18 @@ func get_import_options(preset): name="loop", default_value=false, }, + { + name="bit_depth", + property_hint=PROPERTY_HINT_ENUM, + hint_string="8 Bits,16 Bits", + default_value=SFXRGenerator.WavBits.WAV_BITS_8, + }, + { + name="sample_rate", + property_hint=PROPERTY_HINT_ENUM, + hint_string="44100 Hz,22050 Hz", + default_value=SFXRGenerator.WavFreq.WAV_FREQ_44100, + }, ] @@ -53,7 +65,9 @@ func import(source_file, save_path, options, platform_variants, gen_files): printerr("Failed to open %s: %d" % [source_file, err]) return err - var stream := SFXRGenerator.new().generate_audio_stream(config) + var stream := SFXRGenerator.new().generate_audio_stream( + config, options.bit_depth, options.sample_rate + ) if options.loop: stream.loop_mode = AudioStreamSample.LOOP_FORWARD stream.loop_end = stream.data.size() diff --git a/example/example.sfxr.import b/example/example.sfxr.import index 0420f65..96e8b79 100644 --- a/example/example.sfxr.import +++ b/example/example.sfxr.import @@ -12,3 +12,5 @@ dest_files=[ "res://.import/example.sfxr-e3731bcdcd8403a2391e92667a5d1076.sample [params] loop=false +bit_depth=0 +sample_rate=0