Add import options for bit depth and sample rate

This commit is contained in:
Haoyu Qiu 2023-01-04 17:44:46 +08:00
parent 5b910afb64
commit 576708bb4a
6 changed files with 64 additions and 17 deletions

View File

@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Added ### Added
- Bit depth and sample rate import options.
- Paste from JSXFR. - Paste from JSXFR.
## [1.2.0] - 2022-10-13 ## [1.2.0] - 2022-10-13

View File

@ -32,6 +32,8 @@
如果你希望使用原始的 sfxr 保存出的文件,请确保使用 `.sfxr` 扩展名保存。你也可以在原始的 sfxr 中加载并编辑 `.sfxr` 文件。 如果你希望使用原始的 sfxr 保存出的文件,请确保使用 `.sfxr` 扩展名保存。你也可以在原始的 sfxr 中加载并编辑 `.sfxr` 文件。
`.sfxr` 文件有循环Loop、位深度Bit Depth、采样率Sample Rate等导入选项。可以在 Godot 编辑器的导入面板中找到。
**注意:** 由于 GDScript 的性能限制,生成较长的音效时编辑器可能会有短暂的停滞。只有编辑器会受此影响。在游戏中使用 `.sfxr` 文件是不会在运行时生成任何东西的。 **注意:** 由于 GDScript 的性能限制,生成较长的音效时编辑器可能会有短暂的停滞。只有编辑器会受此影响。在游戏中使用 `.sfxr` 文件是不会在运行时生成任何东西的。
## 更新日志 ## 更新日志

View File

@ -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 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. `.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 **Note:** Due to performance constraints with GDScript, the editor may freeze a bit when generating
long sounds. This only happens in-editor. long sounds. This only happens in-editor.
Using `.sfxr` files in-game won't generate anything at runtime. Using `.sfxr` files in-game won't generate anything at runtime.

View File

@ -5,6 +5,15 @@ const SFXRConfig := preload("SFXRConfig.gd")
const master_vol := 0.05 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 _config: SFXRConfig
var rep_time: int var rep_time: int
@ -41,32 +50,42 @@ var fltdmp: float
var fltphp: 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() var stream := AudioStreamSample.new()
stream.format = AudioStreamSample.FORMAT_8_BITS stream.format = AudioStreamSample.FORMAT_8_BITS if wav_bits == WavBits.WAV_BITS_8 else AudioStreamSample.FORMAT_16_BITS
stream.mix_rate = 44100 stream.mix_rate = 44100 if wav_freq == WavFreq.WAV_FREQ_44100 else 22050
_config = config _config = config
stream.data = _generate_samples() stream.data = _generate_samples(wav_bits, wav_freq).data_array
_config = null _config = null
return stream 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 _config = config
var data := _generate_samples() var data := _generate_samples(wav_bits, wav_freq).data_array
_config = null _config = null
return data return data
func _generate_samples() -> PoolByteArray: func _generate_samples(wav_bits: int, wav_freq: int) -> StreamPeerBuffer:
_reset_sample(true) _reset_sample(true)
var playing_sample := true var playing_sample := true
var env_stage := 0 var env_stage := 0
var env_time := 0 var env_time := 0
var output := PoolByteArray([]) var filesample: float = 0
var fileacc := 0
var buffer := StreamPeerBuffer.new()
# SynthSample # SynthSample
while playing_sample: while playing_sample:
@ -174,15 +193,21 @@ func _generate_samples() -> PoolByteArray:
ssample *= 4.0 # arbitrary gain to get reasonable output volume... ssample *= 4.0 # arbitrary gain to get reasonable output volume...
ssample = clamp(ssample, -1.0, +1.0) 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 if wav_freq == WavFreq.WAV_FREQ_44100 or fileacc == 2:
filesample += 128 filesample /= fileacc
if filesample > 255: fileacc = 0
filesample -= 255
if wav_bits == WavBits.WAV_BITS_8:
output.push_back(filesample) buffer.put_8(filesample * 255)
return output else:
buffer.put_16(filesample * 32000)
filesample = 0
return buffer
func _reset_sample(restart: bool) -> void: func _reset_sample(restart: bool) -> void:

View File

@ -39,6 +39,18 @@ func get_import_options(preset):
name="loop", name="loop",
default_value=false, 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]) printerr("Failed to open %s: %d" % [source_file, err])
return 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: if options.loop:
stream.loop_mode = AudioStreamSample.LOOP_FORWARD stream.loop_mode = AudioStreamSample.LOOP_FORWARD
stream.loop_end = stream.data.size() stream.loop_end = stream.data.size()

View File

@ -12,3 +12,5 @@ dest_files=[ "res://.import/example.sfxr-e3731bcdcd8403a2391e92667a5d1076.sample
[params] [params]
loop=false loop=false
bit_depth=0
sample_rate=0