Compare commits

..

6 Commits
2.0 ... master

Author SHA1 Message Date
d1e4b34cdc Fix everything for Pandemonium. 2023-08-12 10:02:42 +02:00
Haoyu Qiu
7b3194f500 1.3 Release 2023-02-23 21:20:46 +08:00
Haoyu Qiu
4562f4b77c Add default filename for Save As dialog
Trailing number incremented.

Co-Authored-By: Russell Matney <russell.matney@gmail.com>
2023-02-16 09:53:49 +08:00
Haoyu Qiu
576708bb4a Add import options for bit depth and sample rate 2023-01-04 17:49:34 +08:00
Haoyu Qiu
5b910afb64 Implement paste from jsfxr 2022-12-04 14:01:44 +08:00
Haoyu Qiu
9acce6be58 Add Godot 4 information in README 2022-10-16 11:48:06 +08:00
28 changed files with 648 additions and 539 deletions

View File

@ -6,8 +6,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [2.0.0] - 2023-02-23 ## [1.3.0] - 2023-02-23
### Added ### Added
- First release for Godot 4. See the `master` branch for Godot 3 support. - Bit depth and sample rate import options.
- Paste from JSXFR.
- Add default filename for Save As dialog, with trailing number incremented.
[2.0.0]: https://github.com/timothyqiu/gdfxr/releases/tag/2.0 ## [1.2.0] - 2022-10-13
### Added
- Implement custom slider.
## [1.1.1] - 2022-07-30
### Fixed
- Slider min value for a bipolar parameter should be -1.
## [1.1.0] - 2022-03-10
### Added
- Extra options menu: Save As, Copy, and Paste.
- Add a copy of the LICENSE in the plugin folder.
- Keep several recently generated sounds in the menu.
## [1.0.0] - 2022-02-25
### Added
- Initial release.
[1.0.0]: https://github.com/timothyqiu/gdfxr/releases/tag/1.0
[1.1.0]: https://github.com/timothyqiu/gdfxr/releases/tag/1.1
[1.1.1]: https://github.com/timothyqiu/gdfxr/releases/tag/1.1.1
[1.2.0]: https://github.com/timothyqiu/gdfxr/releases/tag/1.2
[1.3.0]: https://github.com/timothyqiu/gdfxr/releases/tag/1.3

View File

@ -10,7 +10,7 @@
你可以在 Godot 中把 sfxr 音效文件当作普通的音频文件使用,也可以像在原始的 sfxr 中一样对音效进行编辑。 你可以在 Godot 中把 sfxr 音效文件当作普通的音频文件使用,也可以像在原始的 sfxr 中一样对音效进行编辑。
> 🚧 如果你想在 Godot 3 里使用这个插件,请移步 [master](https://github.com/timothyqiu/gdfxr/tree/master) 分支。 > 🚧 如果你想在 Godot 4 里使用这个插件,请移步 [godot-4](https://github.com/timothyqiu/gdfxr/tree/godot-4) 分支。
## 安装 ## 安装

View File

@ -12,7 +12,7 @@ the popular program of choice to make retro sound effects for games.
You can use sfxr sound files like regular audio files in Godot and edit sound files like in the You can use sfxr sound files like regular audio files in Godot and edit sound files like in the
original sfxr. original sfxr.
> 🚧 Checkout the [master](https://github.com/timothyqiu/gdfxr/tree/master) branch if you want to use this plugin in Godot 3. > 🚧 Checkout the [godot-4](https://github.com/timothyqiu/gdfxr/tree/godot-4) branch if you want to use this plugin in Godot 4.
## Installation ## Installation

View File

@ -11,7 +11,7 @@ static func b58decode(v: String) -> StreamPeerBuffer:
v = v.lstrip(BASE_58_ALPHABET[0]) v = v.lstrip(BASE_58_ALPHABET[0])
var zeros := original_length - v.length() var zeros := original_length - v.length()
var buffer := PackedByteArray() var buffer := PoolByteArray()
buffer.resize(v.length()) # Won't be as long as base 58 string since the buffer is 256-based. buffer.resize(v.length()) # Won't be as long as base 58 string since the buffer is 256-based.
buffer.fill(0) buffer.fill(0)
@ -32,7 +32,7 @@ static func b58decode(v: String) -> StreamPeerBuffer:
var result := StreamPeerBuffer.new() var result := StreamPeerBuffer.new()
for _i in zeros: for _i in zeros:
result.put_8(0) result.put_8(0)
result.put_data(buffer.slice(buffer.size() - length)) result.put_data(buffer.subarray(buffer.size() - length, -1))
result.seek(0) result.seek(0)
return result return result

View File

@ -55,9 +55,10 @@ var sound_vol := 0.5
func load(path: String) -> int: # Error func load(path: String) -> int: # Error
var f := FileAccess.open(path, FileAccess.READ) var f := File.new()
if not f: var err := f.open(path, File.READ)
return FileAccess.get_open_error() if err != OK:
return err
var version := f.get_32() var version := f.get_32()
if not [100, 101, 102].has(version): if not [100, 101, 102].has(version):
@ -105,9 +106,10 @@ func load(path: String) -> int: # Error
func save(path: String) -> int: # Error func save(path: String) -> int: # Error
var f := FileAccess.open(path, FileAccess.WRITE) var f := File.new()
if not f: var err := f.open(path, File.WRITE)
return FileAccess.get_open_error() if err != OK:
return err
f.store_32(102) f.store_32(102)
f.store_32(wave_type) f.store_32(wave_type)
@ -152,88 +154,88 @@ func randomize_in_category(category: int) -> void:
match category: match category:
Category.PICKUP_COIN: Category.PICKUP_COIN:
p_base_freq = randf_range(0.4, 0.9) p_base_freq = rand_range(0.4, 0.9)
p_env_attack = 0.0 p_env_attack = 0.0
p_env_sustain = randf_range(0.0, 0.1) p_env_sustain = rand_range(0.0, 0.1)
p_env_decay = randf_range(0.1, 0.5) p_env_decay = rand_range(0.1, 0.5)
p_env_punch = randf_range(0.3, 0.6) p_env_punch = rand_range(0.3, 0.6)
if randi() % 2: if randi() % 2:
p_arp_speed = randf_range(0.5, 0.7) p_arp_speed = rand_range(0.5, 0.7)
p_arp_mod = randf_range(0.2, 0.6) p_arp_mod = rand_range(0.2, 0.6)
Category.LASER_SHOOT: Category.LASER_SHOOT:
wave_type = randi() % 3 wave_type = randi() % 3
if wave_type == 2 and randi() % 2: if wave_type == 2 and randi() % 2:
wave_type = randi() % 2 wave_type = randi() % 2
p_base_freq = randf_range(0.5, 1.0) p_base_freq = rand_range(0.5, 1.0)
p_freq_limit = max(0.2, p_base_freq - randf_range(0.2, 0.8)) p_freq_limit = max(0.2, p_base_freq - rand_range(0.2, 0.8))
p_freq_ramp = randf_range(-0.35, -0.15) p_freq_ramp = rand_range(-0.35, -0.15)
if randi() % 3 == 0: if randi() % 3 == 0:
p_base_freq = randf_range(0.3, 0.9) p_base_freq = rand_range(0.3, 0.9)
p_freq_limit = randf_range(0, 0.1) p_freq_limit = rand_range(0, 0.1)
p_freq_ramp = randf_range(-0.65, -0.35) p_freq_ramp = rand_range(-0.65, -0.35)
if randi() % 2: if randi() % 2:
p_duty = randf_range(0, 0.5) p_duty = rand_range(0, 0.5)
p_duty_ramp = randf_range(0, 0.2) p_duty_ramp = rand_range(0, 0.2)
else: else:
p_duty = randf_range(0.4, 0.9) p_duty = rand_range(0.4, 0.9)
p_duty_ramp = randf_range(-0.7, 0) p_duty_ramp = rand_range(-0.7, 0)
p_env_attack = 0.0 p_env_attack = 0.0
p_env_sustain = randf_range(0.1, 0.3) p_env_sustain = rand_range(0.1, 0.3)
p_env_decay = randf_range(0.0, 0.4) p_env_decay = rand_range(0.0, 0.4)
if randi() % 2: if randi() % 2:
p_env_punch = randf_range(0, 0.3) p_env_punch = rand_range(0, 0.3)
if randi() % 3 == 0: if randi() % 3 == 0:
p_pha_offset = randf_range(0, 0.2) p_pha_offset = rand_range(0, 0.2)
p_pha_ramp = randf_range(0, 0.2) p_pha_ramp = rand_range(0, 0.2)
if randi() % 2: if randi() % 2:
p_hpf_freq = randf_range(0, 0.3) p_hpf_freq = rand_range(0, 0.3)
Category.EXPLOSION: Category.EXPLOSION:
wave_type = WaveType.NOISE wave_type = WaveType.NOISE
if randi() % 2: if randi() % 2:
p_base_freq = randf_range(0.1, 0.4) p_base_freq = rand_range(0.1, 0.4)
p_freq_ramp = randf_range(-0.1, 0.3) p_freq_ramp = rand_range(-0.1, 0.3)
else: else:
p_base_freq = randf_range(0.2, 0.9) p_base_freq = rand_range(0.2, 0.9)
p_freq_ramp = randf_range(-0.4, -0.2) p_freq_ramp = rand_range(-0.4, -0.2)
p_base_freq *= p_base_freq p_base_freq *= p_base_freq
if randi() % 5 == 0: if randi() % 5 == 0:
p_freq_ramp = 0.0 p_freq_ramp = 0.0
if randi() % 3 == 0: if randi() % 3 == 0:
p_repeat_speed = randf_range(0.3, 0.8) p_repeat_speed = rand_range(0.3, 0.8)
p_env_attack = 0.0 p_env_attack = 0.0
p_env_sustain = randf_range(0.1, 0.4) p_env_sustain = rand_range(0.1, 0.4)
p_env_decay = randf_range(0, 0.5) p_env_decay = rand_range(0, 0.5)
if randi() % 2: if randi() % 2:
p_pha_offset = randf_range(-0.3, 0.6) p_pha_offset = rand_range(-0.3, 0.6)
p_pha_ramp = randf_range(-0.3, 0) p_pha_ramp = rand_range(-0.3, 0)
p_env_punch = randf_range(0.2, 0.8) p_env_punch = rand_range(0.2, 0.8)
if randi() % 2: if randi() % 2:
p_vib_strength = randf_range(0, 0.7) p_vib_strength = rand_range(0, 0.7)
p_vib_speed = randf_range(0, 0.6) p_vib_speed = rand_range(0, 0.6)
if randi() % 3: if randi() % 3:
p_arp_speed = randf_range(0.6, 0.9) p_arp_speed = rand_range(0.6, 0.9)
p_arp_mod = randf_range(-0.8, 0.8) p_arp_mod = rand_range(-0.8, 0.8)
Category.POWERUP: Category.POWERUP:
if randi() % 2: if randi() % 2:
wave_type = WaveType.SAWTOOTH wave_type = WaveType.SAWTOOTH
else: else:
p_duty = randf_range(0, 0.6) p_duty = rand_range(0, 0.6)
if randi() % 2: if randi() % 2:
p_base_freq = randf_range(0.2, 0.5) p_base_freq = rand_range(0.2, 0.5)
p_freq_ramp = randf_range(0.1, 0.5) p_freq_ramp = rand_range(0.1, 0.5)
p_repeat_speed = randf_range(0.4, 0.8) p_repeat_speed = rand_range(0.4, 0.8)
else: else:
p_base_freq = randf_range(0.2, 0.5) p_base_freq = rand_range(0.2, 0.5)
p_freq_ramp = randf_range(0.05, 0.25) p_freq_ramp = rand_range(0.05, 0.25)
if randi() % 2: if randi() % 2:
p_vib_strength = randf_range(0, 0.7) p_vib_strength = rand_range(0, 0.7)
p_vib_speed = randf_range(0, 0.6) p_vib_speed = rand_range(0, 0.6)
p_env_attack = 0.0 p_env_attack = 0.0
p_env_sustain = randf_range(0, 0.4) p_env_sustain = rand_range(0, 0.4)
p_env_decay = randf_range(0.1, 0.5) p_env_decay = rand_range(0.1, 0.5)
Category.HIT_HURT: Category.HIT_HURT:
wave_type = randi() % 3 wave_type = randi() % 3
@ -241,123 +243,123 @@ func randomize_in_category(category: int) -> void:
WaveType.SINE_WAVE: WaveType.SINE_WAVE:
wave_type = WaveType.NOISE wave_type = WaveType.NOISE
WaveType.SQUARE_WAVE: WaveType.SQUARE_WAVE:
p_duty = randf_range(0, 0.6) p_duty = rand_range(0, 0.6)
p_base_freq = randf_range(0.2, 0.8) p_base_freq = rand_range(0.2, 0.8)
p_freq_ramp = randf_range(-0.7, -0.3) p_freq_ramp = rand_range(-0.7, -0.3)
p_env_attack = 0.0 p_env_attack = 0.0
p_env_sustain = randf_range(0, 0.1) p_env_sustain = rand_range(0, 0.1)
p_env_decay = randf_range(0.1, 0.3) p_env_decay = rand_range(0.1, 0.3)
if randi() % 2: if randi() % 2:
p_hpf_freq = randf_range(0, 0.3) p_hpf_freq = rand_range(0, 0.3)
Category.JUMP: Category.JUMP:
wave_type = WaveType.SQUARE_WAVE wave_type = WaveType.SQUARE_WAVE
p_duty = randf_range(0, 0.6) p_duty = rand_range(0, 0.6)
p_base_freq = randf_range(0.3, 0.6) p_base_freq = rand_range(0.3, 0.6)
p_freq_ramp = randf_range(0.1, 0.3) p_freq_ramp = rand_range(0.1, 0.3)
p_env_attack = 0.0 p_env_attack = 0.0
p_env_sustain = randf_range(0.1, 0.4) p_env_sustain = rand_range(0.1, 0.4)
p_env_decay = randf_range(0.1, 0.3) p_env_decay = rand_range(0.1, 0.3)
if randi() % 2: if randi() % 2:
p_hpf_freq = randf_range(0, 0.3) p_hpf_freq = rand_range(0, 0.3)
if randi() % 2: if randi() % 2:
p_lpf_freq = randf_range(0.4, 1.0) p_lpf_freq = rand_range(0.4, 1.0)
Category.BLIP_SELECT: Category.BLIP_SELECT:
wave_type = randi() % 2 wave_type = randi() % 2
if wave_type == WaveType.SQUARE_WAVE: if wave_type == WaveType.SQUARE_WAVE:
p_duty = randf_range(0, 0.6) p_duty = rand_range(0, 0.6)
p_base_freq = randf_range(0.2, 0.6) p_base_freq = rand_range(0.2, 0.6)
p_env_attack = 0.0 p_env_attack = 0.0
p_env_sustain = randf_range(0.1, 0.2) p_env_sustain = rand_range(0.1, 0.2)
p_env_decay = randf_range(0, 0.2) p_env_decay = rand_range(0, 0.2)
p_hpf_freq = 0.1 p_hpf_freq = 0.1
func randomize() -> void: func randomize() -> void:
p_base_freq = pow(randf_range(-1.0, +1.0), 2.0) p_base_freq = pow(rand_range(-1.0, +1.0), 2.0)
if randi() % 2: if randi() % 2:
p_base_freq = pow(randf_range(-1.0, +1.0), 3.0) + 0.5 p_base_freq = pow(rand_range(-1.0, +1.0), 3.0) + 0.5
p_freq_limit = 0.0 p_freq_limit = 0.0
p_freq_ramp = pow(randf_range(-1.0, +1.0), 5.0) p_freq_ramp = pow(rand_range(-1.0, +1.0), 5.0)
if p_base_freq > 0.7 and p_freq_ramp > 0.2: if p_base_freq > 0.7 and p_freq_ramp > 0.2:
p_freq_ramp = -p_freq_ramp p_freq_ramp = -p_freq_ramp
if p_base_freq < 0.2 and p_freq_ramp < -0.05: if p_base_freq < 0.2 and p_freq_ramp < -0.05:
p_freq_ramp = -p_freq_ramp p_freq_ramp = -p_freq_ramp
p_freq_dramp = pow(randf_range(-1.0, +1.0), 3.0) p_freq_dramp = pow(rand_range(-1.0, +1.0), 3.0)
p_duty = randf_range(-1.0, +1.0) p_duty = rand_range(-1.0, +1.0)
p_duty_ramp = pow(randf_range(-1.0, +1.0), 3.0) p_duty_ramp = pow(rand_range(-1.0, +1.0), 3.0)
p_vib_strength = pow(randf_range(-1.0, +1.0), 3.0) p_vib_strength = pow(rand_range(-1.0, +1.0), 3.0)
p_vib_speed = randf_range(-1.0, +1.0) p_vib_speed = rand_range(-1.0, +1.0)
# p_vib_delay = randf_range(-1.0, +1.0) # p_vib_delay = rand_range(-1.0, +1.0)
p_env_attack = pow(randf_range(-1.0, +1.0), 3.0) p_env_attack = pow(rand_range(-1.0, +1.0), 3.0)
p_env_sustain = pow(randf_range(-1.0, +1.0), 2.0) p_env_sustain = pow(rand_range(-1.0, +1.0), 2.0)
p_env_decay = randf_range(-1.0, +1.0) p_env_decay = rand_range(-1.0, +1.0)
p_env_punch = pow(randf_range(0, 0.8), 2.0) p_env_punch = pow(rand_range(0, 0.8), 2.0)
if p_env_attack + p_env_sustain + p_env_decay < 0.2: if p_env_attack + p_env_sustain + p_env_decay < 0.2:
p_env_sustain += randf_range(0.2, 0.5) p_env_sustain += rand_range(0.2, 0.5)
p_env_decay += randf_range(0.2, 0.5) p_env_decay += rand_range(0.2, 0.5)
p_lpf_resonance = randf_range(-1.0, +1.0) p_lpf_resonance = rand_range(-1.0, +1.0)
p_lpf_freq = 1.0 - pow(randf(), 3.0) p_lpf_freq = 1.0 - pow(randf(), 3.0)
p_lpf_ramp = pow(randf_range(-1.0, +1.0), 3.0) p_lpf_ramp = pow(rand_range(-1.0, +1.0), 3.0)
if p_lpf_freq < 0.1 and p_lpf_ramp < -0.05: if p_lpf_freq < 0.1 and p_lpf_ramp < -0.05:
p_lpf_ramp = -p_lpf_ramp p_lpf_ramp = -p_lpf_ramp
p_hpf_freq = pow(randf(), 5.0) p_hpf_freq = pow(randf(), 5.0)
p_hpf_ramp = pow(randf_range(-1.0, +1.0), 5.0) p_hpf_ramp = pow(rand_range(-1.0, +1.0), 5.0)
p_pha_offset = pow(randf_range(-1.0, +1.0), 3.0) p_pha_offset = pow(rand_range(-1.0, +1.0), 3.0)
p_pha_ramp = pow(randf_range(-1.0, +1.0), 3.0) p_pha_ramp = pow(rand_range(-1.0, +1.0), 3.0)
p_repeat_speed = randf_range(-1.0, +1.0) p_repeat_speed = rand_range(-1.0, +1.0)
p_arp_speed = randf_range(-1.0, +1.0) p_arp_speed = rand_range(-1.0, +1.0)
p_arp_mod = randf_range(-1.0, +1.0) p_arp_mod = rand_range(-1.0, +1.0)
func mutate() -> void: func mutate() -> void:
if randi() % 2: if randi() % 2:
p_base_freq += randf_range(-0.05, +0.05) p_base_freq += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_freq_limit += randf_range(-0.05, +0.05) p_freq_limit += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_freq_ramp += randf_range(-0.05, +0.05) p_freq_ramp += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_freq_dramp += randf_range(-0.05, +0.05) p_freq_dramp += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_duty += randf_range(-0.05, +0.05) p_duty += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_duty_ramp += randf_range(-0.05, +0.05) p_duty_ramp += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_vib_strength += randf_range(-0.05, +0.05) p_vib_strength += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_vib_speed += randf_range(-0.05, +0.05) p_vib_speed += rand_range(-0.05, +0.05)
# if randi() % 2: # if randi() % 2:
# p_vib_delay += randf_range(-0.05, +0.05) # p_vib_delay += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_env_attack += randf_range(-0.05, +0.05) p_env_attack += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_env_sustain += randf_range(-0.05, +0.05) p_env_sustain += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_env_decay += randf_range(-0.05, +0.05) p_env_decay += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_env_punch += randf_range(-0.05, +0.05) p_env_punch += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_lpf_resonance += randf_range(-0.05, +0.05) p_lpf_resonance += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_lpf_freq += randf_range(-0.05, +0.05) p_lpf_freq += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_lpf_ramp += randf_range(-0.05, +0.05) p_lpf_ramp += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_hpf_freq += randf_range(-0.05, +0.05) p_hpf_freq += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_hpf_ramp += randf_range(-0.05, +0.05) p_hpf_ramp += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_pha_offset += randf_range(-0.05, +0.05) p_pha_offset += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_pha_ramp += randf_range(-0.05, +0.05) p_pha_ramp += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_repeat_speed += randf_range(-0.05, +0.05) p_repeat_speed += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_arp_speed += randf_range(-0.05, +0.05) p_arp_speed += rand_range(-0.05, +0.05)
if randi() % 2: if randi() % 2:
p_arp_mod += randf_range(-0.05, +0.05) p_arp_mod += rand_range(-0.05, +0.05)
func reset(): func reset():
@ -395,7 +397,7 @@ func reset():
p_arp_mod = 0.0 p_arp_mod = 0.0
func copy_from(other: RefCounted) -> void: # SFXRConfig func copy_from(other: Reference) -> void: # SFXRConfig
wave_type = other.wave_type wave_type = other.wave_type
p_env_attack = other.p_env_attack p_env_attack = other.p_env_attack
@ -430,7 +432,7 @@ func copy_from(other: RefCounted) -> void: # SFXRConfig
sound_vol = other.sound_vol sound_vol = other.sound_vol
func is_equal(other: RefCounted) -> bool: # SFXRConfig func is_equal(other: Reference) -> bool: # SFXRConfig
return ( return (
wave_type == other.wave_type wave_type == other.wave_type

View File

@ -32,15 +32,15 @@ var vib_speed: float
var square_duty: float var square_duty: float
var square_slide: float var square_slide: float
var env_vol: float var env_vol: float
var env_length := PackedInt32Array([0, 0, 0]) var env_length := PoolIntArray([0, 0, 0])
var phase: int var phase: int
var fphase: float var fphase: float
var fdphase: float var fdphase: float
var iphase: int var iphase: int
var flthp: float var flthp: float
var flthp_d: float var flthp_d: float
var noise_buffer := PackedFloat32Array([]) var noise_buffer := PoolRealArray([])
var phaser_buffer := PackedFloat32Array([]) var phaser_buffer := PoolRealArray([])
var ipp: int var ipp: int
var fltp: float var fltp: float
var fltdp: float var fltdp: float
@ -54,9 +54,9 @@ func generate_audio_stream(
config: SFXRConfig, config: SFXRConfig,
wav_bits: int = WavBits.WAV_BITS_8, wav_bits: int = WavBits.WAV_BITS_8,
wav_freq: int = WavFreq.WAV_FREQ_44100 wav_freq: int = WavFreq.WAV_FREQ_44100
) -> AudioStreamWAV: ) -> AudioStreamSample:
var stream := AudioStreamWAV.new() var stream := AudioStreamSample.new()
stream.format = AudioStreamWAV.FORMAT_8_BITS if wav_bits == WavBits.WAV_BITS_8 else AudioStreamWAV.FORMAT_16_BITS 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 stream.mix_rate = 44100 if wav_freq == WavFreq.WAV_FREQ_44100 else 22050
_config = config _config = config
@ -70,7 +70,7 @@ func generate_samples(
config: SFXRConfig, config: SFXRConfig,
wav_bits: int = WavBits.WAV_BITS_8, wav_bits: int = WavBits.WAV_BITS_8,
wav_freq: int = WavFreq.WAV_FREQ_44100 wav_freq: int = WavFreq.WAV_FREQ_44100
) -> PackedByteArray: ) -> PoolByteArray:
_config = config _config = config
var data := _generate_samples(wav_bits, wav_freq).data_array var data := _generate_samples(wav_bits, wav_freq).data_array
_config = null _config = null
@ -148,7 +148,7 @@ func _generate_samples(wav_bits: int, wav_freq: int) -> StreamPeerBuffer:
phase %= period phase %= period
if _config.wave_type == SFXRConfig.WaveType.NOISE: if _config.wave_type == SFXRConfig.WaveType.NOISE:
for j in 32: for j in 32:
noise_buffer[j] = randf_range(-1.0, +1.0) noise_buffer[j] = rand_range(-1.0, +1.0)
# base waveform # base waveform
var fp := float(phase) / period var fp := float(phase) / period
@ -266,7 +266,7 @@ func _reset_sample(restart: bool) -> void:
noise_buffer.resize(32) noise_buffer.resize(32)
for i in noise_buffer.size(): for i in noise_buffer.size():
noise_buffer[i] = randf_range(-1.0, +1.0) noise_buffer[i] = rand_range(-1.0, +1.0)
rep_time = 0 rep_time = 0
rep_limit = int(pow(1.0 - _config.p_repeat_speed, 2.0) * 20000 + 32) rep_limit = int(pow(1.0 - _config.p_repeat_speed, 2.0) * 20000 + 32)

View File

@ -1,12 +1,11 @@
@tool tool
extends Control extends Control
signal value_changed(value) signal value_changed(value)
@export var value: float = 0.0 : export var value: float = 0.0 setget set_value
set = set_value export var min_value: float = 0.0
@export var min_value: float = 0.0 export var max_value: float = 1.0
@export var max_value: float = 1.0
var _line_edit: LineEdit var _line_edit: LineEdit
@ -18,7 +17,6 @@ var _stylebox_value: StyleBox
var _line_edit_just_closed := false var _line_edit_just_closed := false
var _mouse_hovering := false var _mouse_hovering := false
var _is_editing := false var _is_editing := false
var _is_cancel := false
var _drag_start_position: Vector2 var _drag_start_position: Vector2
var _drag_cancelled := true var _drag_cancelled := true
@ -26,9 +24,9 @@ var _drag_dist := 0.0
var _drag_start_factor: float var _drag_start_factor: float
func _init(): func _init() -> void:
mouse_default_cursor_shape = Control.CURSOR_HSIZE mouse_default_cursor_shape = Control.CURSOR_HSIZE
clip_contents = true rect_clip_content = true
focus_mode = Control.FOCUS_ALL focus_mode = Control.FOCUS_ALL
var style := StyleBoxEmpty.new() var style := StyleBoxEmpty.new()
@ -36,51 +34,49 @@ func _init():
style.content_margin_right = 8 style.content_margin_right = 8
_line_edit = LineEdit.new() _line_edit = LineEdit.new()
_line_edit.set_as_top_level(true) _line_edit.set_as_toplevel(true)
_line_edit.visible = false _line_edit.visible = false
_line_edit.add_theme_stylebox_override("normal", style) _line_edit.add_theme_stylebox_override("normal", style)
_line_edit.add_theme_stylebox_override("focus", StyleBoxEmpty.new()) _line_edit.add_theme_stylebox_override("focus", StyleBoxEmpty.new())
var _ret: int var _ret: int
_ret = _line_edit.focus_exited.connect(self._on_line_edit_focus_exited) _ret = _line_edit.connect("focus_exited", self, "_on_line_edit_focus_exited")
_ret = _line_edit.text_submitted.connect(self._on_line_edit_text_entered) _ret = _line_edit.connect("text_entered", self, "_on_line_edit_text_entered")
_ret = _line_edit.visibility_changed.connect(self._on_line_edit_visibility_changed) _ret = _line_edit.connect("visibility_changed", self, "_on_line_edit_visibility_changed")
_ret = _line_edit.gui_input.connect(self._on_line_edit_gui_input)
add_child(_line_edit) add_child(_line_edit)
func _draw() -> void: func _draw() -> void:
var font := get_theme_font("font", "LineEdit") var font := get_theme_font("font", "LineEdit")
var font_size := get_theme_font_size("font_size", "LineEdit")
var color := get_theme_color("highlighted_font_color" if _mouse_hovering else "font_color", "Editor") var color := get_theme_color("highlighted_font_color" if _mouse_hovering else "font_color", "Editor")
var number_string := "%.3f" % value var number_string := "%.3f" % value
var number_size := font.get_string_size(number_string) var number_size := font.get_string_size(number_string)
var pos := Vector2( var pos := Vector2(
(size.x - number_size.x) / 2, (rect_size.x - number_size.x) / 2,
(size.y - number_size.y) / 2 + font.get_ascent() (rect_size.y - number_size.y) / 2 + font.get_ascent()
) )
var stylebox := _stylebox_editing if _is_editing else _stylebox_hover if _mouse_hovering else _stylebox_normal var stylebox := _stylebox_editing if _is_editing else _stylebox_hover if _mouse_hovering else _stylebox_normal
if _line_edit.visible: if _line_edit.visible:
draw_style_box(stylebox, Rect2(Vector2.ZERO, size)) draw_style_box(stylebox, Rect2(Vector2.ZERO, rect_size))
else: else:
var value_width := size.x * ((value - min_value) / (max_value - min_value)) var value_width := rect_size.x * ((value - min_value) / (max_value - min_value))
draw_style_box(stylebox, Rect2(value_width, 0, size.x - value_width, size.y)) draw_style_box(stylebox, Rect2(value_width, 0, rect_size.x - value_width, rect_size.y))
draw_style_box(_stylebox_value, Rect2(0, 0, value_width, size.y)) draw_style_box(_stylebox_value, Rect2(0, 0, value_width, rect_size.y))
draw_string(font, pos, number_string, HORIZONTAL_ALIGNMENT_CENTER, -1, font_size, color) draw_string(font, pos, number_string, color)
func _get_minimum_size() -> Vector2: func _get_minimum_size() -> Vector2:
var ms := _stylebox_normal.get_minimum_size() if _stylebox_normal else Vector2.ZERO var ms := _stylebox_normal.get_minimum_size()
ms.y += get_theme_font("font", "LineEdit").get_height() ms.y += get_theme_font("font", "LineEdit").get_height()
return ms return ms
func _gui_input(event: InputEvent) -> void: func _gui_input(event: InputEvent) -> void:
var mb := event as InputEventMouseButton var mb := event as InputEventMouseButton
if mb and mb.button_index == MOUSE_BUTTON_LEFT: if mb and mb.button_index == BUTTON_LEFT:
if mb.pressed: if mb.pressed:
_drag_prepare(mb) _drag_prepare(mb)
else: else:
@ -89,10 +85,10 @@ func _gui_input(event: InputEvent) -> void:
_show_text_edit() _show_text_edit()
_drag_cancelled = true _drag_cancelled = true
_is_editing = mb.pressed _is_editing = mb.pressed
queue_redraw() update()
var mm := event as InputEventMouseMotion var mm := event as InputEventMouseMotion
if mm and mm.button_mask & MOUSE_BUTTON_MASK_LEFT: if mm and mm.button_mask & BUTTON_MASK_LEFT:
_drag_motion(mm) _drag_motion(mm)
_drag_cancelled = false _drag_cancelled = false
@ -104,11 +100,11 @@ func _notification(what: int) -> void:
NOTIFICATION_MOUSE_ENTER: NOTIFICATION_MOUSE_ENTER:
_mouse_hovering = true _mouse_hovering = true
queue_redraw() update()
NOTIFICATION_MOUSE_EXIT: NOTIFICATION_MOUSE_EXIT:
_mouse_hovering = false _mouse_hovering = false
queue_redraw() update()
NOTIFICATION_FOCUS_ENTER: NOTIFICATION_FOCUS_ENTER:
if (Input.is_action_pressed("ui_focus_next") or Input.is_action_pressed("ui_focus_prev")) and not _line_edit_just_closed: if (Input.is_action_pressed("ui_focus_next") or Input.is_action_pressed("ui_focus_prev")) and not _line_edit_just_closed:
@ -121,7 +117,7 @@ func set_value(v: float) -> void:
return return
value = v value = v
emit_signal("value_changed", value) emit_signal("value_changed", value)
queue_redraw() update()
func _update_stylebox() -> void: func _update_stylebox() -> void:
@ -145,9 +141,9 @@ func _drag_done() -> void:
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
if _drag_cancelled: if _drag_cancelled:
Input.warp_mouse(_drag_start_position) Input.warp_mouse_position(_drag_start_position)
else: else:
Input.warp_mouse(global_position + size * Vector2( Input.warp_mouse_position(rect_global_position + rect_size * Vector2(
(value - min_value) / (max_value - min_value), (value - min_value) / (max_value - min_value),
0.5 0.5
)) ))
@ -156,33 +152,32 @@ func _drag_done() -> void:
func _drag_motion(motion: InputEventMouseMotion) -> void: func _drag_motion(motion: InputEventMouseMotion) -> void:
_drag_dist += motion.relative.x _drag_dist += motion.relative.x
var factor := _drag_start_factor + _drag_dist / size.x var factor := _drag_start_factor + _drag_dist / rect_size.x
if factor < 0 or 1 < factor: if factor < 0 or 1 < factor:
factor = clamp(factor, 0, 1) factor = clamp(factor, 0, 1)
_drag_dist = (factor - _drag_start_factor) * size.x _drag_dist = (factor - _drag_start_factor) * rect_size.x
var v := factor * (max_value - min_value) + min_value var v := factor * (max_value - min_value) + min_value
var snap := motion.is_command_or_control_pressed() or motion.shift_pressed var snap := motion.command or motion.shift
if snap and not (is_equal_approx(v, min_value) or is_equal_approx(v, max_value)): if snap and not (is_equal_approx(v, min_value) or is_equal_approx(v, max_value)):
if motion.shift_pressed and motion.is_command_or_control_pressed(): if motion.shift and motion.command:
v = round(v * 1000.0) * 0.001 v = round(v * 1000.0) * 0.001
elif motion.shift_pressed: elif motion.shift:
v = round(v * 100.0) * 0.01 v = round(v * 100.0) * 0.01
else: else:
v = round(v * 10.0) * 0.1 v = round(v * 10.0) * 0.1
set_value(clamp(v, min_value, max_value)) set_value(clamp(v, min_value, max_value))
queue_redraw() update()
func _show_text_edit() -> void: func _show_text_edit() -> void:
var gr := get_global_rect() var gr := get_global_rect()
_is_cancel = false
_line_edit.text = str(value) _line_edit.text = str(value)
_line_edit.set_position(gr.position) _line_edit.set_position(gr.position)
_line_edit.set_size(gr.size) _line_edit.set_size(gr.size)
_line_edit.show() # FIXME: no suitable solution for `show_modal` yet _line_edit.show_modal()
_line_edit.select_all() _line_edit.select_all()
_line_edit.grab_focus() _line_edit.grab_focus()
_line_edit.focus_next = find_next_valid_focus().get_path() _line_edit.focus_next = find_next_valid_focus().get_path()
@ -192,11 +187,11 @@ func _show_text_edit() -> void:
func _on_line_edit_focus_exited(): func _on_line_edit_focus_exited():
if _line_edit.get_menu().visible: if _line_edit.get_menu().visible:
return return
if not _is_cancel and _line_edit.text.is_valid_float(): if _line_edit.text.is_valid_float():
set_value(clamp(_line_edit.text.to_float(), min_value, max_value)) set_value(clamp(_line_edit.text.to_float(), min_value, max_value))
if not _line_edit_just_closed: if not _line_edit_just_closed:
_line_edit.hide() _line_edit.hide()
queue_redraw() update()
func _on_line_edit_text_entered(_text: String): func _on_line_edit_text_entered(_text: String):
@ -206,9 +201,3 @@ func _on_line_edit_text_entered(_text: String):
func _on_line_edit_visibility_changed(): func _on_line_edit_visibility_changed():
if not _line_edit.visible: if not _line_edit.visible:
_line_edit_just_closed = true _line_edit_just_closed = true
func _on_line_edit_gui_input(event: InputEvent):
if event.is_action_pressed("ui_cancel"):
_is_cancel = true
_line_edit.hide()

View File

@ -1,4 +1,4 @@
@tool tool
extends Container extends Container
enum ExtraOption { SAVE_AS, COPY, PASTE, PASTE_JSFXR, RECENT } enum ExtraOption { SAVE_AS, COPY, PASTE, PASTE_JSFXR, RECENT }
@ -13,11 +13,7 @@ class RecentEntry:
var title: String var title: String
var config := SFXRConfig.new() var config := SFXRConfig.new()
var plugin: EditorPlugin: var plugin: EditorPlugin
set(v):
plugin = v
for child in get_children():
_hook_plugin(child)
var _config := SFXRConfig.new() var _config := SFXRConfig.new()
var _config_defaults := SFXRConfig.new() var _config_defaults := SFXRConfig.new()
@ -31,44 +27,47 @@ var _param_map := {}
var _syncing_ui := false # a hack since Range set_value emits value_changed var _syncing_ui := false # a hack since Range set_value emits value_changed
var _category_names := {} var _category_names := {}
@onready var audio_player := $AudioStreamPlayer as AudioStreamPlayer onready var audio_player := $AudioStreamPlayer as AudioStreamPlayer
@onready var filename_label := find_child("Filename") as Label onready var filename_label := find_node("Filename") as Label
@onready var save_button := find_child("Save") as Button onready var save_button := find_node("Save") as Button
@onready var restore_button := find_child("Restore") as Button onready var restore_button := find_node("Restore") as Button
@onready var extra_button := find_child("Extra") as MenuButton onready var extra_button := find_node("Extra") as MenuButton
@onready var version_button := find_child("VersionButton") onready var version_button := find_node("VersionButton")
@onready var translator := $PluginTranslator onready var translator := $PluginTranslator
func _ready(): func _ready():
if not plugin: if not plugin:
return # Running in the edited scene instead of from Plugin return # Running in the edited scene instead of from Plugin
for child in get_children():
_hook_plugin(child)
var popup := extra_button.get_popup() var popup := extra_button.get_popup()
popup.add_item(translator.t("Save As..."), ExtraOption.SAVE_AS) popup.add_item(translator.tr("Save As..."), ExtraOption.SAVE_AS)
popup.add_separator() popup.add_separator()
popup.add_icon_item(get_theme_icon("ActionCopy", "EditorIcons"), translator.t("Copy"), ExtraOption.COPY) popup.add_item(translator.tr("Copy"), ExtraOption.COPY)
popup.add_icon_item(get_theme_icon("ActionPaste", "EditorIcons"), translator.t("Paste"), ExtraOption.PASTE) popup.add_item(translator.tr("Paste"), ExtraOption.PASTE)
popup.add_item(translator.t("Paste from jsfxr"), ExtraOption.PASTE_JSFXR) popup.add_item(translator.tr("Paste from jsfxr"), ExtraOption.PASTE_JSFXR)
popup.add_separator(translator.t("Recently Generated")) popup.add_separator(translator.tr("Recently Generated"))
popup.id_pressed.connect(_on_Extra_id_pressed) popup.connect("id_pressed", self, "_on_Extra_id_pressed")
_category_names = { _category_names = {
SFXRConfig.Category.PICKUP_COIN: translator.t("Pickup/Coin"), SFXRConfig.Category.PICKUP_COIN: translator.tr("Pickup/Coin"),
SFXRConfig.Category.LASER_SHOOT: translator.t("Laser/Shoot"), SFXRConfig.Category.LASER_SHOOT: translator.tr("Laser/Shoot"),
SFXRConfig.Category.EXPLOSION: translator.t("Explosion"), SFXRConfig.Category.EXPLOSION: translator.tr("Explosion"),
SFXRConfig.Category.POWERUP: translator.t("Powerup"), SFXRConfig.Category.POWERUP: translator.tr("Powerup"),
SFXRConfig.Category.HIT_HURT: translator.t("Hit/Hurt"), SFXRConfig.Category.HIT_HURT: translator.tr("Hit/Hurt"),
SFXRConfig.Category.JUMP: translator.t("Jump"), SFXRConfig.Category.JUMP: translator.tr("Jump"),
SFXRConfig.Category.BLIP_SELECT: translator.t("Blip/Select"), SFXRConfig.Category.BLIP_SELECT: translator.tr("Blip/Select"),
} }
var params := find_child("Params") as Container var params := find_node("Params") as Container
for category in params.get_children(): for category in params.get_children():
for control in category.get_children(): for control in category.get_children():
_param_map[control.parameter] = control _param_map[control.parameter] = control
control.connect("param_changed", _on_param_changed) control.connect("param_changed", self, "_on_param_changed")
control.connect("param_reset", _on_param_reset) control.connect("param_reset", self, "_on_param_reset")
_set_editing_file("") _set_editing_file("")
@ -79,7 +78,7 @@ func _notification(what: int):
match what: match what:
NOTIFICATION_ENTER_TREE, NOTIFICATION_THEME_CHANGED: NOTIFICATION_ENTER_TREE, NOTIFICATION_THEME_CHANGED:
find_child("ScrollContainer").add_theme_stylebox_override("panel", get_theme_stylebox("panel", "Tree")) find_node("ScrollContainer").add_theme_stylebox_override("bg", get_theme_stylebox("bg", "Tree"))
if extra_button: if extra_button:
var popup = extra_button.get_popup() var popup = extra_button.get_popup()
@ -87,18 +86,11 @@ func _notification(what: int):
popup.set_item_icon(popup.get_item_index(ExtraOption.PASTE), get_theme_icon("ActionPaste", "EditorIcons")) popup.set_item_icon(popup.get_item_index(ExtraOption.PASTE), get_theme_icon("ActionPaste", "EditorIcons"))
func edit(object: Variant) -> void: func edit(path: String) -> void:
if not object:
if not _modified:
_set_editing_file("")
# TODO: prompt?
return
var path := object.resource_path as String
if _modified: if _modified:
_popup_confirm( _popup_confirm(
translator.t("There are unsaved changes.\nOpen '%s' anyway?") % path, str(translator.tr("There are unsaved changes.\nOpen '%s' anyway?")) % path,
_set_editing_file.bind(path) "_set_editing_file", [path]
) )
else: else:
_set_editing_file(path) _set_editing_file(path)
@ -125,30 +117,30 @@ func _push_recent(title: String) -> void:
_config_recents.push_front(recent) _config_recents.push_front(recent)
func _popup_confirm(content: String, callback: Callable) -> void: func _popup_confirm(content: String, callback: String, binds := []) -> void:
var dialog := ConfirmationDialog.new() var dialog := ConfirmationDialog.new()
add_child(dialog) add_child(dialog)
dialog.dialog_text = content dialog.dialog_text = content
dialog.title = translator.t("SFXR Editor") dialog.window_title = translator.tr("SFXR Editor")
dialog.confirmed.connect(callback) dialog.connect("confirmed", self, callback, binds)
dialog.connect("popup_hide", dialog, "queue_free")
dialog.popup_centered() dialog.popup_centered()
dialog.visibility_changed.connect(dialog.queue_free)
func _popup_message(content: String) -> void: func _popup_message(content: String) -> void:
var dialog := AcceptDialog.new() var dialog := AcceptDialog.new()
add_child(dialog) add_child(dialog)
dialog.dialog_text = content dialog.dialog_text = content
dialog.title = translator.t("SFXR Editor") dialog.window_title = translator.tr("SFXR Editor")
dialog.connect("popup_hide", dialog, "queue_free")
dialog.popup_centered() dialog.popup_centered()
dialog.visibility_changed.connect(dialog.queue_free)
func _popup_file_dialog(mode: int, callback: Callable, default_filename := DefaultFilename.EMPTY) -> void: func _popup_file_dialog(mode: int, callback: String, default_filename: int = DefaultFilename.EMPTY) -> void:
var dialog := EditorFileDialog.new() var dialog := EditorFileDialog.new()
add_child(dialog) add_child(dialog)
dialog.access = EditorFileDialog.ACCESS_RESOURCES dialog.access = EditorFileDialog.ACCESS_RESOURCES
dialog.file_mode = mode dialog.mode = mode
match default_filename: match default_filename:
DefaultFilename.EMPTY: DefaultFilename.EMPTY:
@ -158,10 +150,10 @@ func _popup_file_dialog(mode: int, callback: Callable, default_filename := Defau
if _path: if _path:
dialog.current_path = _generate_serial_path(_path) dialog.current_path = _generate_serial_path(_path)
dialog.add_filter("*.sfxr; %s" % translator.t("SFXR Audio")) dialog.add_filter("*.sfxr; %s" % translator.tr("SFXR Audio"))
dialog.file_selected.connect(callback) dialog.connect("popup_hide", dialog, "queue_free")
dialog.connect("file_selected", self, callback)
dialog.popup_centered_ratio() dialog.popup_centered_ratio()
dialog.visibility_changed.connect(dialog.queue_free)
func _reset_defaults() -> void: func _reset_defaults() -> void:
@ -178,13 +170,13 @@ func _restore_from_config(config: SFXRConfig) -> void:
func _set_editing_file(path: String) -> int: # Error func _set_editing_file(path: String) -> int: # Error
if path.is_empty(): if path.empty():
_config.reset() _config.reset()
audio_player.stream = null audio_player.stream = null
else: else:
var err := _config.load(path) var err := _config.load(path)
if err != OK: if err != OK:
_popup_message(translator.t("'%s' is not a valid SFXR file.") % path) _popup_message(str(translator.tr("'%s' is not a valid SFXR file.")) % path)
return err return err
audio_player.stream = load(path) audio_player.stream = load(path)
@ -196,8 +188,8 @@ func _set_editing_file(path: String) -> int: # Error
func _set_modified(value: bool) -> void: func _set_modified(value: bool) -> void:
_modified = value _modified = value
var has_file := not _path.is_empty() var has_file := not _path.empty()
var base = _path if has_file else translator.t("Unsaved sound") var base = _path if has_file else str(translator.tr("Unsaved sound"))
if _modified: if _modified:
base += "(*)" base += "(*)"
filename_label.text = base filename_label.text = base
@ -216,8 +208,8 @@ func _sync_ui() -> void:
func _generate_serial_path(path: String) -> String: func _generate_serial_path(path: String) -> String:
var directory := DirAccess.open(path.get_base_dir()) var directory := Directory.new()
if not directory: if directory.open(path.get_base_dir()) != OK:
return path return path
if not directory.file_exists(path.get_file()): if not directory.file_exists(path.get_file()):
@ -281,7 +273,7 @@ func _on_Play_pressed(force_regenerate := false):
func _on_Randomize_pressed(category: int): func _on_Randomize_pressed(category: int):
if category == -1: if category == -1:
_config.randomize() _config.randomize()
_push_recent(translator.t("Randomize")) _push_recent(translator.tr("Randomize"))
else: else:
_config.randomize_in_category(category) _config.randomize_in_category(category)
_push_recent(_category_names.get(category, "Unknown")) _push_recent(_category_names.get(category, "Unknown"))
@ -294,7 +286,7 @@ func _on_Randomize_pressed(category: int):
func _on_Mutate_pressed(): func _on_Mutate_pressed():
_config.mutate() _config.mutate()
_push_recent(translator.t("Mutate")) _push_recent(translator.tr("Mutate"))
_set_modified(true) _set_modified(true)
_sync_ui() _sync_ui()
_on_Play_pressed(true) _on_Play_pressed(true)
@ -307,8 +299,8 @@ func _on_Restore_pressed():
func _on_New_pressed(): func _on_New_pressed():
if _modified: if _modified:
_popup_confirm( _popup_confirm(
translator.t("There are unsaved changes.\nCreate a new one anyway?"), translator.tr("There are unsaved changes.\nCreate a new one anyway?"),
_on_New_confirmed "_on_New_confirmed"
) )
else: else:
_on_New_confirmed() _on_New_confirmed()
@ -319,8 +311,8 @@ func _on_New_confirmed() -> void:
func _on_Save_pressed(): func _on_Save_pressed():
if _path.is_empty(): if _path.empty():
_popup_file_dialog(EditorFileDialog.FILE_MODE_SAVE_FILE, _on_SaveAsDialog_confirmed) _popup_file_dialog(EditorFileDialog.MODE_SAVE_FILE, "_on_SaveAsDialog_confirmed")
else: else:
_config.save(_path) _config.save(_path)
plugin.get_editor_interface().get_resource_filesystem().scan_sources() plugin.get_editor_interface().get_resource_filesystem().scan_sources()
@ -337,17 +329,17 @@ func _on_SaveAsDialog_confirmed(path: String):
func _on_Load_pressed(): func _on_Load_pressed():
if _modified: if _modified:
_popup_confirm( _popup_confirm(
translator.t("There are unsaved changes.\nLoad anyway?"), translator.tr("There are unsaved changes.\nLoad anyway?"),
_popup_file_dialog.bind(EditorFileDialog.FILE_MODE_OPEN_FILE, "_set_editing_file") "_popup_file_dialog", [EditorFileDialog.MODE_OPEN_FILE, "_set_editing_file"]
) )
else: else:
_popup_file_dialog(EditorFileDialog.FILE_MODE_OPEN_FILE, _set_editing_file) _popup_file_dialog(EditorFileDialog.MODE_OPEN_FILE, "_set_editing_file")
func _on_Extra_about_to_show(): func _on_Extra_about_to_show():
var popup := extra_button.get_popup() var popup := extra_button.get_popup()
popup.set_item_disabled(popup.get_item_index(ExtraOption.PASTE), _config_clipboard == null) popup.set_item_disabled(popup.get_item_index(ExtraOption.PASTE), _config_clipboard == null)
popup.set_item_disabled(popup.get_item_index(ExtraOption.PASTE_JSFXR), not DisplayServer.clipboard_has()) popup.set_item_disabled(popup.get_item_index(ExtraOption.PASTE_JSFXR), not OS.has_clipboard())
# Rebuild recents menu everytime :) # Rebuild recents menu everytime :)
var first_recent_index := popup.get_item_index(ExtraOption.RECENT) var first_recent_index := popup.get_item_index(ExtraOption.RECENT)
@ -356,8 +348,8 @@ func _on_Extra_about_to_show():
for i in count - first_recent_index: for i in count - first_recent_index:
popup.remove_item(count - 1 - i) popup.remove_item(count - 1 - i)
if _config_recents.is_empty(): if _config_recents.empty():
popup.add_item(translator.t("None"), ExtraOption.RECENT) popup.add_item(translator.tr("None"), ExtraOption.RECENT)
popup.set_item_disabled(popup.get_item_index(ExtraOption.RECENT), true) popup.set_item_disabled(popup.get_item_index(ExtraOption.RECENT), true)
else: else:
for i in _config_recents.size(): for i in _config_recents.size():
@ -367,7 +359,7 @@ func _on_Extra_about_to_show():
func _on_Extra_id_pressed(id: int) -> void: func _on_Extra_id_pressed(id: int) -> void:
match id: match id:
ExtraOption.SAVE_AS: ExtraOption.SAVE_AS:
_popup_file_dialog(EditorFileDialog.FILE_MODE_SAVE_FILE, _on_SaveAsDialog_confirmed, DefaultFilename.GUESS_FOR_SAVE) _popup_file_dialog(EditorFileDialog.MODE_SAVE_FILE, "_on_SaveAsDialog_confirmed", DefaultFilename.GUESS_FOR_SAVE)
ExtraOption.COPY: ExtraOption.COPY:
if not _config_clipboard: if not _config_clipboard:
@ -379,10 +371,10 @@ func _on_Extra_id_pressed(id: int) -> void:
ExtraOption.PASTE_JSFXR: ExtraOption.PASTE_JSFXR:
var pasted := SFXRConfig.new() var pasted := SFXRConfig.new()
if pasted.load_from_base58(DisplayServer.clipboard_get()) == OK: if pasted.load_from_base58(OS.clipboard) == OK:
_restore_from_config(pasted) _restore_from_config(pasted)
else: else:
_popup_message(translator.t("Clipboard does not contain code copied from jsfxr.")) _popup_message(translator.tr("Clipboard does not contain code copied from jsfxr."))
_: _:
var i := id - ExtraOption.RECENT as int var i := id - ExtraOption.RECENT as int

View File

@ -1,297 +1,394 @@
[gd_scene load_steps=7 format=3 uid="uid://dv8q33r8aan5b"] [gd_scene load_steps=7 format=2]
[ext_resource type="Script" path="res://addons/gdfxr/editor/EditorIconButton.gd" id="1"] [ext_resource path="res://addons/gdfxr/editor/EditorIconButton.gd" type="Script" id=1]
[ext_resource type="Script" path="res://addons/gdfxr/editor/Editor.gd" id="2"] [ext_resource path="res://addons/gdfxr/editor/Editor.gd" type="Script" id=2]
[ext_resource type="PackedScene" uid="uid://p27e3x3kk5e0" path="res://addons/gdfxr/editor/ParamSlider.tscn" id="3"] [ext_resource path="res://addons/gdfxr/editor/ParamSlider.tscn" type="PackedScene" id=3]
[ext_resource type="PackedScene" uid="uid://b8wt6fq8w6mxc" path="res://addons/gdfxr/editor/ParamOption.tscn" id="4"] [ext_resource path="res://addons/gdfxr/editor/ParamOption.tscn" type="PackedScene" id=4]
[ext_resource type="PackedScene" uid="uid://cewvefxbttrds" path="res://addons/gdfxr/editor/PluginTranslator.tscn" id="5"] [ext_resource path="res://addons/gdfxr/editor/PluginTranslator.tscn" type="PackedScene" id=5]
[ext_resource type="PackedScene" path="res://addons/gdfxr/editor/VersionButton.tscn" id="6"] [ext_resource path="res://addons/gdfxr/editor/VersionButton.tscn" type="PackedScene" id=6]
[node name="Editor" type="VBoxContainer"] [node name="Editor" type="VBoxContainer"]
anchors_preset = 15
anchor_right = 1.0 anchor_right = 1.0
anchor_bottom = 1.0 anchor_bottom = 1.0
grow_horizontal = 2 script = ExtResource( 2 )
grow_vertical = 2
script = ExtResource("2")
[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] [node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."]
[node name="Toolbar" type="HBoxContainer" parent="."] [node name="Toolbar" type="HBoxContainer" parent="."]
layout_mode = 2 margin_right = 1024.0
margin_bottom = 22.0
[node name="New" type="Button" parent="Toolbar"] [node name="New" type="ToolButton" parent="Toolbar"]
layout_mode = 2 margin_right = 12.0
tooltip_text = "New" margin_bottom = 22.0
flat = true hint_tooltip = "New"
script = ExtResource("1") script = ExtResource( 1 )
icon_name = "New" icon_name = "New"
[node name="Load" type="Button" parent="Toolbar"] [node name="Load" type="ToolButton" parent="Toolbar"]
layout_mode = 2 margin_left = 16.0
tooltip_text = "Load" margin_right = 28.0
flat = true margin_bottom = 22.0
script = ExtResource("1") hint_tooltip = "Load"
script = ExtResource( 1 )
icon_name = "Load" icon_name = "Load"
[node name="Save" type="Button" parent="Toolbar"] [node name="Save" type="ToolButton" parent="Toolbar"]
layout_mode = 2 margin_left = 32.0
tooltip_text = "Save" margin_right = 44.0
flat = true margin_bottom = 22.0
script = ExtResource("1") hint_tooltip = "Save"
script = ExtResource( 1 )
icon_name = "Save" icon_name = "Save"
[node name="Extra" type="MenuButton" parent="Toolbar"] [node name="Extra" type="MenuButton" parent="Toolbar"]
layout_mode = 2 margin_left = 48.0
tooltip_text = "Extra Options" margin_right = 60.0
script = ExtResource("1") margin_bottom = 22.0
hint_tooltip = "Extra Options"
script = ExtResource( 1 )
icon_name = "GuiTabMenuHl" icon_name = "GuiTabMenuHl"
[node name="VSeparator" type="VSeparator" parent="Toolbar"] [node name="VSeparator" type="VSeparator" parent="Toolbar"]
layout_mode = 2 margin_left = 64.0
margin_right = 68.0
margin_bottom = 22.0
[node name="Play" type="Button" parent="Toolbar"] [node name="Play" type="Button" parent="Toolbar"]
layout_mode = 2 margin_left = 72.0
margin_right = 152.0
margin_bottom = 22.0
rect_min_size = Vector2( 80, 0 )
size_flags_horizontal = 0 size_flags_horizontal = 0
text = "Play" text = "Play"
script = ExtResource("1") script = ExtResource( 1 )
icon_name = "Play" icon_name = "Play"
[node name="Restore" type="Button" parent="Toolbar"] [node name="Restore" type="Button" parent="Toolbar"]
layout_mode = 2 margin_left = 156.0
tooltip_text = "Restore" margin_right = 236.0
margin_bottom = 22.0
rect_min_size = Vector2( 80, 0 )
hint_tooltip = "Restore"
disabled = true disabled = true
text = "Restore" text = "Restore"
script = ExtResource("1") script = ExtResource( 1 )
icon_name = "Reload" icon_name = "Reload"
[node name="VSeparator2" type="VSeparator" parent="Toolbar"] [node name="VSeparator2" type="VSeparator" parent="Toolbar"]
layout_mode = 2 margin_left = 240.0
margin_right = 244.0
margin_bottom = 22.0
[node name="Filename" type="Label" parent="Toolbar"] [node name="Filename" type="Label" parent="Toolbar"]
layout_mode = 2 margin_left = 248.0
margin_top = 4.0
margin_right = 1020.0
margin_bottom = 18.0
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "Unsaved sound" text = "Unsaved sound"
clip_text = true clip_text = true
[node name="VersionButton" parent="Toolbar" instance=ExtResource("6")] [node name="VersionButton" parent="Toolbar" instance=ExtResource( 6 )]
layout_mode = 2 margin_top = 4.0
margin_bottom = 18.0
website = "https://github.com/timothyqiu/gdfxr" website = "https://github.com/timothyqiu/gdfxr"
[node name="HSeparator" type="HSeparator" parent="."] [node name="HSeparator" type="HSeparator" parent="."]
layout_mode = 2 margin_top = 26.0
margin_right = 1024.0
margin_bottom = 30.0
[node name="Editor" type="HBoxContainer" parent="."] [node name="Editor" type="HBoxContainer" parent="."]
layout_mode = 2 margin_top = 34.0
margin_right = 1024.0
margin_bottom = 600.0
size_flags_vertical = 3 size_flags_vertical = 3
[node name="Generators" type="VBoxContainer" parent="Editor"] [node name="Generators" type="VBoxContainer" parent="Editor"]
layout_mode = 2 margin_right = 128.0
margin_bottom = 566.0
rect_min_size = Vector2( 128, 0 )
[node name="Button" type="Button" parent="Editor/Generators"] [node name="Button" type="Button" parent="Editor/Generators"]
layout_mode = 2 margin_right = 128.0
margin_bottom = 20.0
text = "Pickup/Coin" text = "Pickup/Coin"
[node name="Button2" type="Button" parent="Editor/Generators"] [node name="Button2" type="Button" parent="Editor/Generators"]
layout_mode = 2 margin_top = 24.0
margin_right = 128.0
margin_bottom = 44.0
text = "Laser/Shoot" text = "Laser/Shoot"
[node name="Button3" type="Button" parent="Editor/Generators"] [node name="Button3" type="Button" parent="Editor/Generators"]
layout_mode = 2 margin_top = 48.0
margin_right = 128.0
margin_bottom = 68.0
text = "Explosion" text = "Explosion"
[node name="Button4" type="Button" parent="Editor/Generators"] [node name="Button4" type="Button" parent="Editor/Generators"]
layout_mode = 2 margin_top = 72.0
margin_right = 128.0
margin_bottom = 92.0
text = "Powerup" text = "Powerup"
[node name="Button5" type="Button" parent="Editor/Generators"] [node name="Button5" type="Button" parent="Editor/Generators"]
layout_mode = 2 margin_top = 96.0
margin_right = 128.0
margin_bottom = 116.0
text = "Hit/Hurt" text = "Hit/Hurt"
[node name="Button6" type="Button" parent="Editor/Generators"] [node name="Button6" type="Button" parent="Editor/Generators"]
layout_mode = 2 margin_top = 120.0
margin_right = 128.0
margin_bottom = 140.0
text = "Jump" text = "Jump"
[node name="Button7" type="Button" parent="Editor/Generators"] [node name="Button7" type="Button" parent="Editor/Generators"]
layout_mode = 2 margin_top = 144.0
margin_right = 128.0
margin_bottom = 164.0
text = "Blip/Select" text = "Blip/Select"
[node name="HSeparator" type="HSeparator" parent="Editor/Generators"] [node name="HSeparator" type="HSeparator" parent="Editor/Generators"]
layout_mode = 2 margin_top = 168.0
margin_right = 128.0
margin_bottom = 172.0
[node name="Button8" type="Button" parent="Editor/Generators"] [node name="Button8" type="Button" parent="Editor/Generators"]
layout_mode = 2 margin_top = 176.0
margin_right = 128.0
margin_bottom = 196.0
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "Mutate" text = "Mutate"
[node name="Button9" type="Button" parent="Editor/Generators"] [node name="Button9" type="Button" parent="Editor/Generators"]
layout_mode = 2 margin_top = 200.0
margin_right = 128.0
margin_bottom = 220.0
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "Randomize" text = "Randomize"
[node name="ScrollContainer" type="ScrollContainer" parent="Editor"] [node name="ScrollContainer" type="ScrollContainer" parent="Editor"]
layout_mode = 2 margin_left = 132.0
margin_right = 1024.0
margin_bottom = 566.0
size_flags_horizontal = 3 size_flags_horizontal = 3
scroll_vertical_enabled = false
[node name="Params" type="HBoxContainer" parent="Editor/ScrollContainer"] [node name="Params" type="HBoxContainer" parent="Editor/ScrollContainer"]
layout_mode = 2 margin_top = 188.0
margin_right = 895.0
margin_bottom = 366.0
size_flags_horizontal = 6 size_flags_horizontal = 6
size_flags_vertical = 6 size_flags_vertical = 6
[node name="Envolope" type="VBoxContainer" parent="Editor/ScrollContainer/Params"] [node name="Envolope" type="VBoxContainer" parent="Editor/ScrollContainer/Params"]
layout_mode = 2 margin_right = 211.0
margin_bottom = 178.0
[node name="ParamSlider" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource("3")] [node name="ParamSlider" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource( 3 )]
layout_mode = 2 margin_right = 211.0
margin_bottom = 22.0
label = "Attack Time" label = "Attack Time"
parameter = "p_env_attack" parameter = "p_env_attack"
[node name="ParamSlider2" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource("3")] [node name="ParamSlider2" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 26.0
margin_right = 211.0
margin_bottom = 48.0
label = "Sustain Time" label = "Sustain Time"
parameter = "p_env_sustain" parameter = "p_env_sustain"
[node name="ParamSlider3" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource("3")] [node name="ParamSlider3" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 52.0
margin_right = 211.0
margin_bottom = 74.0
label = "Sustain Punch" label = "Sustain Punch"
parameter = "p_env_punch" parameter = "p_env_punch"
[node name="ParamSlider4" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource("3")] [node name="ParamSlider4" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 78.0
margin_right = 211.0
margin_bottom = 100.0
label = "Decay Time" label = "Decay Time"
parameter = "p_env_decay" parameter = "p_env_decay"
[node name="ParamSlider5" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource("3")] [node name="ParamSlider5" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 104.0
margin_right = 211.0
margin_bottom = 126.0
label = "Change Amount" label = "Change Amount"
parameter = "p_arp_mod" parameter = "p_arp_mod"
bipolar = true bipolar = true
[node name="ParamSlider6" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource("3")] [node name="ParamSlider6" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 130.0
margin_right = 211.0
margin_bottom = 152.0
label = "Change Speed" label = "Change Speed"
parameter = "p_arp_speed" parameter = "p_arp_speed"
[node name="ParamSlider7" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource("3")] [node name="ParamSlider7" parent="Editor/ScrollContainer/Params/Envolope" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 156.0
margin_right = 211.0
margin_bottom = 178.0
label = "Volume" label = "Volume"
parameter = "sound_vol" parameter = "sound_vol"
[node name="Frequency" type="VBoxContainer" parent="Editor/ScrollContainer/Params"] [node name="Frequency" type="VBoxContainer" parent="Editor/ScrollContainer/Params"]
layout_mode = 2 margin_left = 215.0
margin_right = 425.0
margin_bottom = 178.0
[node name="ParamSlider" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource("3")] [node name="ParamSlider" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource( 3 )]
layout_mode = 2 margin_right = 210.0
margin_bottom = 22.0
label = "Start Frequency" label = "Start Frequency"
parameter = "p_base_freq" parameter = "p_base_freq"
[node name="ParamSlider2" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource("3")] [node name="ParamSlider2" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 26.0
margin_right = 210.0
margin_bottom = 48.0
label = "Min Frequency" label = "Min Frequency"
parameter = "p_freq_limit" parameter = "p_freq_limit"
[node name="ParamSlider3" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource("3")] [node name="ParamSlider3" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 52.0
margin_right = 210.0
margin_bottom = 74.0
label = "Slide" label = "Slide"
parameter = "p_freq_ramp" parameter = "p_freq_ramp"
bipolar = true bipolar = true
[node name="ParamSlider4" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource("3")] [node name="ParamSlider4" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 78.0
margin_right = 210.0
margin_bottom = 100.0
label = "Delta Slide" label = "Delta Slide"
parameter = "p_freq_dramp" parameter = "p_freq_dramp"
bipolar = true bipolar = true
[node name="ParamSlider5" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource("3")] [node name="ParamSlider5" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 104.0
margin_right = 210.0
margin_bottom = 126.0
label = "Vibrato Depth" label = "Vibrato Depth"
parameter = "p_vib_strength" parameter = "p_vib_strength"
[node name="ParamSlider6" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource("3")] [node name="ParamSlider6" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 130.0
margin_right = 210.0
margin_bottom = 152.0
label = "Vibrato Speed" label = "Vibrato Speed"
parameter = "p_vib_speed" parameter = "p_vib_speed"
[node name="ParamSlider7" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource("3")] [node name="ParamSlider7" parent="Editor/ScrollContainer/Params/Frequency" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 156.0
margin_right = 210.0
margin_bottom = 178.0
label = "Repeat Speed" label = "Repeat Speed"
parameter = "p_repeat_speed" parameter = "p_repeat_speed"
[node name="Waveform" type="VBoxContainer" parent="Editor/ScrollContainer/Params"] [node name="Waveform" type="VBoxContainer" parent="Editor/ScrollContainer/Params"]
layout_mode = 2 margin_left = 429.0
margin_right = 649.0
margin_bottom = 178.0
[node name="WaveformOption" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource("4")] [node name="WaveformOption" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource( 4 )]
layout_mode = 2 margin_right = 220.0
options = ["Square", "Sawtooth", "Sine", "Noise"] margin_bottom = 22.0
options = [ "Square", "Sawtooth", "Sine", "Noise" ]
parameter = "wave_type" parameter = "wave_type"
[node name="ParamSlider" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource("3")] [node name="ParamSlider" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 26.0
margin_right = 220.0
margin_bottom = 48.0
label = "Square Duty" label = "Square Duty"
parameter = "p_duty" parameter = "p_duty"
[node name="ParamSlider2" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource("3")] [node name="ParamSlider2" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 52.0
margin_right = 220.0
margin_bottom = 74.0
label = "Duty Sweep" label = "Duty Sweep"
parameter = "p_duty_ramp" parameter = "p_duty_ramp"
bipolar = true bipolar = true
[node name="ParamSlider5" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource("3")] [node name="ParamSlider5" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 78.0
margin_right = 220.0
margin_bottom = 100.0
label = "Phaser Offset" label = "Phaser Offset"
parameter = "p_pha_offset" parameter = "p_pha_offset"
bipolar = true bipolar = true
[node name="ParamSlider3" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource("3")] [node name="ParamSlider3" parent="Editor/ScrollContainer/Params/Waveform" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 104.0
margin_right = 220.0
margin_bottom = 126.0
label = "Phaser Sweep" label = "Phaser Sweep"
parameter = "p_pha_ramp" parameter = "p_pha_ramp"
bipolar = true bipolar = true
[node name="Filter" type="VBoxContainer" parent="Editor/ScrollContainer/Params"] [node name="Filter" type="VBoxContainer" parent="Editor/ScrollContainer/Params"]
layout_mode = 2 margin_left = 653.0
margin_right = 895.0
margin_bottom = 178.0
[node name="ParamSlider" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource("3")] [node name="ParamSlider" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource( 3 )]
layout_mode = 2 margin_right = 242.0
margin_bottom = 22.0
label = "Low-pass Cutoff" label = "Low-pass Cutoff"
parameter = "p_lpf_freq" parameter = "p_lpf_freq"
[node name="ParamSlider2" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource("3")] [node name="ParamSlider2" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 26.0
margin_right = 242.0
margin_bottom = 48.0
label = "Low-pass Sweep" label = "Low-pass Sweep"
parameter = "p_lpf_ramp" parameter = "p_lpf_ramp"
bipolar = true bipolar = true
[node name="ParamSlider5" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource("3")] [node name="ParamSlider5" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 52.0
margin_right = 242.0
margin_bottom = 74.0
label = "Low-pass Resonance" label = "Low-pass Resonance"
parameter = "p_lpf_resonance" parameter = "p_lpf_resonance"
[node name="ParamSlider3" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource("3")] [node name="ParamSlider3" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 78.0
margin_right = 242.0
margin_bottom = 100.0
label = "High-pass Cutoff" label = "High-pass Cutoff"
parameter = "p_hpf_freq" parameter = "p_hpf_freq"
[node name="ParamSlider4" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource("3")] [node name="ParamSlider4" parent="Editor/ScrollContainer/Params/Filter" instance=ExtResource( 3 )]
layout_mode = 2 margin_top = 104.0
margin_right = 242.0
margin_bottom = 126.0
label = "High-pass Sweep" label = "High-pass Sweep"
parameter = "p_hpf_ramp" parameter = "p_hpf_ramp"
bipolar = true bipolar = true
[node name="PluginTranslator" parent="." instance=ExtResource("5")] [node name="PluginTranslator" parent="." instance=ExtResource( 5 )]
[connection signal="pressed" from="Toolbar/New" to="." method="_on_New_pressed"] [connection signal="pressed" from="Toolbar/New" to="." method="_on_New_pressed"]
[connection signal="pressed" from="Toolbar/Load" to="." method="_on_Load_pressed"] [connection signal="pressed" from="Toolbar/Load" to="." method="_on_Load_pressed"]
[connection signal="pressed" from="Toolbar/Save" to="." method="_on_Save_pressed"] [connection signal="pressed" from="Toolbar/Save" to="." method="_on_Save_pressed"]
[connection signal="about_to_popup" from="Toolbar/Extra" to="." method="_on_Extra_about_to_show"] [connection signal="about_to_show" from="Toolbar/Extra" to="." method="_on_Extra_about_to_show"]
[connection signal="pressed" from="Toolbar/Play" to="." method="_on_Play_pressed"] [connection signal="pressed" from="Toolbar/Play" to="." method="_on_Play_pressed"]
[connection signal="pressed" from="Toolbar/Restore" to="." method="_on_Restore_pressed"] [connection signal="pressed" from="Toolbar/Restore" to="." method="_on_Restore_pressed"]
[connection signal="pressed" from="Editor/Generators/Button" to="." method="_on_Randomize_pressed" binds= [0]] [connection signal="pressed" from="Editor/Generators/Button" to="." method="_on_Randomize_pressed" binds= [ 0 ]]
[connection signal="pressed" from="Editor/Generators/Button2" to="." method="_on_Randomize_pressed" binds= [1]] [connection signal="pressed" from="Editor/Generators/Button2" to="." method="_on_Randomize_pressed" binds= [ 1 ]]
[connection signal="pressed" from="Editor/Generators/Button3" to="." method="_on_Randomize_pressed" binds= [2]] [connection signal="pressed" from="Editor/Generators/Button3" to="." method="_on_Randomize_pressed" binds= [ 2 ]]
[connection signal="pressed" from="Editor/Generators/Button4" to="." method="_on_Randomize_pressed" binds= [3]] [connection signal="pressed" from="Editor/Generators/Button4" to="." method="_on_Randomize_pressed" binds= [ 3 ]]
[connection signal="pressed" from="Editor/Generators/Button5" to="." method="_on_Randomize_pressed" binds= [4]] [connection signal="pressed" from="Editor/Generators/Button5" to="." method="_on_Randomize_pressed" binds= [ 4 ]]
[connection signal="pressed" from="Editor/Generators/Button6" to="." method="_on_Randomize_pressed" binds= [5]] [connection signal="pressed" from="Editor/Generators/Button6" to="." method="_on_Randomize_pressed" binds= [ 5 ]]
[connection signal="pressed" from="Editor/Generators/Button7" to="." method="_on_Randomize_pressed" binds= [6]] [connection signal="pressed" from="Editor/Generators/Button7" to="." method="_on_Randomize_pressed" binds= [ 6 ]]
[connection signal="pressed" from="Editor/Generators/Button8" to="." method="_on_Mutate_pressed"] [connection signal="pressed" from="Editor/Generators/Button8" to="." method="_on_Mutate_pressed"]
[connection signal="pressed" from="Editor/Generators/Button9" to="." method="_on_Randomize_pressed" binds= [-1]] [connection signal="pressed" from="Editor/Generators/Button9" to="." method="_on_Randomize_pressed" binds= [ -1 ]]

View File

@ -1,7 +1,7 @@
@tool tool
extends Button extends Button
@export var icon_name: String export var icon_name: String
var plugin: EditorPlugin # a hack to know if this is executing as plugin var plugin: EditorPlugin # a hack to know if this is executing as plugin

View File

@ -1,14 +1,13 @@
@tool tool
extends HBoxContainer extends HBoxContainer
signal param_changed(name, value) signal param_changed(name, value)
signal param_reset(name) signal param_reset(name)
@export var options: Array : export var options: Array setget set_options
set = set_options export var parameter: String # Could be PoolStringArray, but pybabel won't catch that
@export var parameter: String # Could be PackedStringArray, but pybabel won't catch that
@onready var option_button := $OptionButton as OptionButton onready var option_button := $OptionButton as OptionButton
func _ready(): func _ready():

View File

@ -1,34 +1,42 @@
[gd_scene load_steps=3 format=3 uid="uid://b8wt6fq8w6mxc"] [gd_scene load_steps=3 format=2]
[ext_resource type="Script" path="res://addons/gdfxr/editor/ParamOption.gd" id="1"] [ext_resource path="res://addons/gdfxr/editor/ParamOption.gd" type="Script" id=1]
[ext_resource type="Script" path="res://addons/gdfxr/editor/EditorIconButton.gd" id="2"] [ext_resource path="res://addons/gdfxr/editor/EditorIconButton.gd" type="Script" id=2]
[node name="WaveformOption" type="HBoxContainer"] [node name="WaveformOption" type="HBoxContainer"]
offset_right = 253.0 margin_right = 253.0
offset_bottom = 40.0 margin_bottom = 40.0
pivot_offset = Vector2(41, -65) rect_pivot_offset = Vector2( 41, -65 )
size_flags_horizontal = 3 size_flags_horizontal = 3
script = ExtResource("1") script = ExtResource( 1 )
[node name="Label" type="Label" parent="."] [node name="Label" type="Label" parent="."]
custom_minimum_size = Vector2(100, 0) margin_top = 13.0
layout_mode = 2 margin_right = 128.0
margin_bottom = 27.0
rect_min_size = Vector2( 100, 0 )
size_flags_horizontal = 3 size_flags_horizontal = 3
text = "Waveform" text = "Waveform"
horizontal_alignment = 2 align = 2
[node name="OptionButton" type="OptionButton" parent="."] [node name="OptionButton" type="OptionButton" parent="."]
custom_minimum_size = Vector2(105, 0) margin_left = 132.0
layout_mode = 2 margin_top = 10.0
margin_right = 237.0
margin_bottom = 30.0
rect_min_size = Vector2( 105, 0 )
size_flags_vertical = 4 size_flags_vertical = 4
clip_text = true clip_text = true
[node name="Reset" type="Button" parent="."] [node name="Reset" type="ToolButton" parent="."]
layout_mode = 2 margin_left = 241.0
size_flags_vertical = 4 margin_top = 9.0
margin_right = 253.0
margin_bottom = 31.0
focus_mode = 0 focus_mode = 0
flat = true size_flags_vertical = 4
script = ExtResource("2") enabled_focus_mode = 0
script = ExtResource( 2 )
icon_name = "ReloadSmall" icon_name = "ReloadSmall"
[connection signal="item_selected" from="OptionButton" to="." method="_on_OptionButton_item_selected"] [connection signal="item_selected" from="OptionButton" to="." method="_on_OptionButton_item_selected"]

View File

@ -1,33 +1,21 @@
@tool tool
extends HBoxContainer extends HBoxContainer
signal param_changed(name, value) signal param_changed(name, value)
signal param_reset(name) signal param_reset(name)
@export var label: String : export var label: String setget set_label
set = set_label export var parameter: String
@export var parameter: String export var bipolar := false setget set_bipolar
@export var bipolar := false :
set = set_bipolar
func _ready():
set_label(label)
set_bipolar(bipolar)
func set_label(v: String) -> void: func set_label(v: String) -> void:
label = v label = v
if is_inside_tree(): $Label.text = v
$Label.text = v
func set_bipolar(v: bool) -> void: func set_bipolar(v: bool) -> void:
bipolar = v bipolar = v
if not is_inside_tree():
return
if bipolar: if bipolar:
$HSlider.min_value = -1.0 $HSlider.min_value = -1.0
else: else:

View File

@ -1,35 +1,41 @@
[gd_scene load_steps=4 format=3 uid="uid://p27e3x3kk5e0"] [gd_scene load_steps=4 format=2]
[ext_resource type="Script" path="res://addons/gdfxr/editor/ParamSlider.gd" id="1"] [ext_resource path="res://addons/gdfxr/editor/ParamSlider.gd" type="Script" id=1]
[ext_resource type="Script" path="res://addons/gdfxr/editor/EditorIconButton.gd" id="2"] [ext_resource path="res://addons/gdfxr/editor/EditorIconButton.gd" type="Script" id=2]
[ext_resource type="Script" path="res://addons/gdfxr/editor/EditSlider.gd" id="3"] [ext_resource path="res://addons/gdfxr/editor/EditSlider.gd" type="Script" id=3]
[node name="ParamSlider" type="HBoxContainer"] [node name="ParamSlider" type="HBoxContainer"]
offset_right = 253.0 margin_right = 253.0
offset_bottom = 40.0 margin_bottom = 40.0
size_flags_horizontal = 3 size_flags_horizontal = 3
script = ExtResource("1") script = ExtResource( 1 )
[node name="Label" type="Label" parent="."] [node name="Label" type="Label" parent="."]
custom_minimum_size = Vector2(100, 0) margin_top = 13.0
layout_mode = 2 margin_right = 128.0
margin_bottom = 27.0
rect_min_size = Vector2( 100, 0 )
size_flags_horizontal = 3 size_flags_horizontal = 3
horizontal_alignment = 2 align = 2
[node name="HSlider" type="Control" parent="."] [node name="HSlider" type="Control" parent="."]
clip_contents = true margin_left = 132.0
custom_minimum_size = Vector2(105, 0) margin_right = 237.0
layout_mode = 2 margin_bottom = 40.0
rect_min_size = Vector2( 105, 0 )
rect_clip_content = true
focus_mode = 2 focus_mode = 2
mouse_default_cursor_shape = 10 mouse_default_cursor_shape = 10
script = ExtResource("3") script = ExtResource( 3 )
[node name="Reset" type="Button" parent="."] [node name="Reset" type="ToolButton" parent="."]
layout_mode = 2 margin_left = 241.0
size_flags_vertical = 4 margin_top = 9.0
margin_right = 253.0
margin_bottom = 31.0
focus_mode = 0 focus_mode = 0
flat = true size_flags_vertical = 4
script = ExtResource("2") script = ExtResource( 2 )
icon_name = "ReloadSmall" icon_name = "ReloadSmall"
[connection signal="value_changed" from="HSlider" to="." method="_on_HSlider_value_changed"] [connection signal="value_changed" from="HSlider" to="." method="_on_HSlider_value_changed"]

View File

@ -1,8 +1,7 @@
@tool tool
extends Node extends Node
var plugin: EditorPlugin : var plugin: EditorPlugin setget set_plugin
set = set_plugin
var _translation: Translation var _translation: Translation
@ -18,40 +17,40 @@ func set_plugin(v: EditorPlugin) -> void:
plugin = v plugin = v
var locale: String = plugin.get_editor_interface().get_editor_settings().get('interface/editor/editor_language') var locale: String = plugin.get_editor_interface().get_editor_settings().get('interface/editor/editor_language')
var script := get_script() as Script var script := get_script() as Script
var path := script.resource_path.get_base_dir().path_join("translations/%s.po" % locale) var path := script.resource_path.get_base_dir().plus_file("translations/%s.po" % locale)
if ResourceLoader.exists(path): if ResourceLoader.exists(path):
_translation = ResourceLoader.load(path) _translation = ResourceLoader.load(path)
if _translation: if _translation:
_translate_node.call_deferred(get_parent()) _translate_node(get_parent())
func t(message: StringName) -> String: func tr(message: StringName) -> StringName:
if _translation: if _translation:
var translated := _translation.get_message(message) var translated := _translation.get_message(message)
if translated: if translated != "":
return String(translated) return translated
return String(message) return message
func _translate_node(node: Node): func _translate_node(node: Node):
if node is Control: if node is Control:
node.tooltip_text = t(node.tooltip_text) node.hint_tooltip = tr(node.hint_tooltip)
if node is HBoxContainer and node.has_method("set_options"): if node is HBoxContainer and node.has_method("set_options"):
var options = [] var options = []
for item in node.options: for item in node.options:
options.append(t(item)) options.append(tr(item))
node.options = options node.options = options
if node is Button and not node is OptionButton: if node is Button and not node is OptionButton:
node.text = t(node.text) node.text = tr(node.text)
if node is Label: if node is Label:
node.text = t(node.text) node.text = tr(node.text)
if node is Slider: if node is Slider:
node.tooltip_text = t(node.tooltip_text) node.hint_tooltip = tr(node.hint_tooltip)
for child in node.get_children(): for child in node.get_children():
_translate_node(child) _translate_node(child)

View File

@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cewvefxbttrds"] [gd_scene load_steps=2 format=2]
[ext_resource type="Script" path="res://addons/gdfxr/editor/PluginTranslator.gd" id="1"] [ext_resource path="res://addons/gdfxr/editor/PluginTranslator.gd" type="Script" id=1]
[node name="PluginTranslator" type="Node"] [node name="PluginTranslator" type="Node"]
script = ExtResource("1") script = ExtResource( 1 )

View File

@ -1,17 +1,16 @@
@tool tool
extends LinkButton extends LinkButton
@export var website: String export var website: String
var plugin: EditorPlugin : var plugin: EditorPlugin setget set_plugin
set = set_plugin
func set_plugin(v: EditorPlugin) -> void: func set_plugin(v: EditorPlugin) -> void:
plugin = v plugin = v
var script := get_script() as Script var script := get_script() as Script
var path := script.resource_path.get_base_dir().path_join("../plugin.cfg") var path := script.resource_path.get_base_dir().plus_file("../plugin.cfg")
var cfg := ConfigFile.new() var cfg := ConfigFile.new()
var err := cfg.load(path) var err := cfg.load(path)

View File

@ -4,10 +4,10 @@
[node name="VersionButton" type="LinkButton"] [node name="VersionButton" type="LinkButton"]
self_modulate = Color( 1, 1, 1, 0.65 ) self_modulate = Color( 1, 1, 1, 0.65 )
offset_left = 1024.0 margin_left = 1024.0
offset_top = 5.0 margin_top = 5.0
offset_right = 1024.0 margin_right = 1024.0
offset_bottom = 19.0 margin_bottom = 19.0
focus_mode = 2 focus_mode = 2
size_flags_vertical = 4 size_flags_vertical = 4
underline = 1 underline = 1

View File

@ -1,72 +1,64 @@
@tool tool
extends EditorImportPlugin extends EditorImportPlugin
const SFXRConfig = preload("SFXRConfig.gd") const SFXRConfig = preload("SFXRConfig.gd")
const SFXRGenerator = preload("SFXRGenerator.gd") const SFXRGenerator = preload("SFXRGenerator.gd")
func _get_importer_name(): func get_importer_name():
return "com.timothyqiu.gdfxr.importer" return "com.timothyqiu.gdfxr.importer"
func _get_import_order(): func get_visible_name():
return ResourceImporter.IMPORT_ORDER_DEFAULT
func _get_priority():
return 1.0
func _get_visible_name():
return "SFXR Audio" return "SFXR Audio"
func _get_recognized_extensions(): func get_recognized_extensions():
return ["sfxr"] return ["sfxr"]
func _get_save_extension(): func get_save_extension():
return "sample" return "sample"
func _get_resource_type(): func get_resource_type():
return "AudioStreamWAV" return "AudioStreamSample"
func _get_preset_count(): func get_preset_count():
return 1 return 1
func _get_preset_name(preset): func get_preset_name(preset):
return "Default" return "Default"
func _get_import_options(path, preset): func get_import_options(preset):
return [ return [
{ {
name="loop", "name":"loop",
default_value=false, "default_value":false,
}, },
{ {
name="bit_depth", "name":"bit_depth",
property_hint=PROPERTY_HINT_ENUM, "property_hint":PROPERTY_HINT_ENUM,
hint_string="8 Bits,16 Bits", "hint_string":"8 Bits,16 Bits",
default_value=SFXRGenerator.WavBits.WAV_BITS_8, "default_value":SFXRGenerator.WavBits.WAV_BITS_8,
}, },
{ {
name="sample_rate", "name":"sample_rate",
property_hint=PROPERTY_HINT_ENUM, "property_hint":PROPERTY_HINT_ENUM,
hint_string="44100 Hz,22050 Hz", "hint_string":"44100 Hz,22050 Hz",
default_value=SFXRGenerator.WavFreq.WAV_FREQ_44100, "default_value":SFXRGenerator.WavFreq.WAV_FREQ_44100,
}, },
] ]
func _get_option_visibility(path, option, options): func get_option_visibility(option, options):
return true return true
func _import(source_file, save_path, options, platform_variants, gen_files): func import(source_file, save_path, options, platform_variants, gen_files):
var config := SFXRConfig.new() var config := SFXRConfig.new()
var err := config.load(source_file) var err := config.load(source_file)
if err != OK: if err != OK:
@ -77,8 +69,8 @@ func _import(source_file, save_path, options, platform_variants, gen_files):
config, options.bit_depth, options.sample_rate config, options.bit_depth, options.sample_rate
) )
if options.loop: if options.loop:
stream.loop_mode = AudioStreamWAV.LOOP_FORWARD stream.loop_mode = AudioStreamSample.LOOP_FORWARD
stream.loop_end = stream.data.size() stream.loop_end = stream.data.size()
var filename = save_path + "." + _get_save_extension() var filename = save_path + "." + get_save_extension()
return ResourceSaver.save(stream, filename) return ResourceSaver.save(filename, stream)

View File

@ -3,5 +3,5 @@
name="gdfxr" name="gdfxr"
description="A Godot plugin that ports sfxr, the popular program of choice to make retro sound effects for games." description="A Godot plugin that ports sfxr, the popular program of choice to make retro sound effects for games."
author="Haoyu Qiu" author="Haoyu Qiu"
version="2.0" version="1.3"
script="plugin.gd" script="plugin.gd"

View File

@ -1,4 +1,4 @@
@tool tool
extends EditorPlugin extends EditorPlugin
@ -10,7 +10,7 @@ func _enter_tree():
import_plugin = preload("import_plugin.gd").new() import_plugin = preload("import_plugin.gd").new()
add_import_plugin(import_plugin) add_import_plugin(import_plugin)
sfxr_editor = preload("editor/Editor.tscn").instantiate() sfxr_editor = preload("editor/Editor.tscn").instance()
sfxr_editor.plugin = self sfxr_editor.plugin = self
add_control_to_bottom_panel(sfxr_editor, "gdfxr") add_control_to_bottom_panel(sfxr_editor, "gdfxr")
@ -24,15 +24,15 @@ func _exit_tree():
import_plugin = null import_plugin = null
func _handles(object: Object) -> bool: func handles(object: Object) -> bool:
return object is AudioStreamWAV and object.resource_path.ends_with(".sfxr") return object is AudioStreamSample and object.resource_path.ends_with(".sfxr")
func _edit(object: Object): func edit(object: Object):
sfxr_editor.edit(object) sfxr_editor.edit(object.resource_path) # Should already passed `handles()` checks
func _make_visible(visible: bool): func make_visible(visible: bool):
if visible: if visible:
make_bottom_panel_item_visible(sfxr_editor) make_bottom_panel_item_visible(sfxr_editor)
elif sfxr_editor.is_visible_in_tree(): elif sfxr_editor.is_visible_in_tree():

View File

@ -4,8 +4,8 @@ extends Container
const SFXRConfig = preload("res://addons/gdfxr/SFXRConfig.gd") const SFXRConfig = preload("res://addons/gdfxr/SFXRConfig.gd")
const SFXRGenerator = preload("res://addons/gdfxr/SFXRGenerator.gd") const SFXRGenerator = preload("res://addons/gdfxr/SFXRGenerator.gd")
@onready var audio_player: AudioStreamPlayer = $AudioPlayer onready var audio_player: AudioStreamPlayer = $AudioPlayer
@onready var adhoc_audio_player: AudioStreamPlayer = $AdhocAudioPlayer onready var adhoc_audio_player: AudioStreamPlayer = $AdhocAudioPlayer
func _on_Play_pressed() -> void: func _on_Play_pressed() -> void:

View File

@ -1,58 +1,73 @@
[gd_scene load_steps=3 format=3 uid="uid://bv31mn2hs6wom"] [gd_scene load_steps=3 format=2]
[ext_resource type="Script" path="res://example/Example.gd" id="1"] [ext_resource path="res://example/Example.gd" type="Script" id=1]
[ext_resource type="AudioStream" uid="uid://byf7u7a25fuf4" path="res://example/example.sfxr" id="2"] [ext_resource path="res://example/example.sfxr" type="AudioStream" id=2]
[node name="Example" type="GridContainer"] [node name="Example" type="GridContainer"]
anchors_preset = 8
anchor_left = 0.5 anchor_left = 0.5
anchor_top = 0.5 anchor_top = 0.5
anchor_right = 0.5 anchor_right = 0.5
anchor_bottom = 0.5 anchor_bottom = 0.5
grow_horizontal = 2 grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
theme_override_constants/h_separation = 32 custom_constants/hseparation = 32
theme_override_constants/v_separation = 32 custom_constants/vseparation = 32
columns = 2 columns = 2
script = ExtResource("1") script = ExtResource( 1 )
[node name="AudioPlayer" type="AudioStreamPlayer" parent="."] [node name="AudioPlayer" type="AudioStreamPlayer" parent="."]
stream = ExtResource("2") stream = ExtResource( 2 )
[node name="AdhocAudioPlayer" type="AudioStreamPlayer" parent="."] [node name="AdhocAudioPlayer" type="AudioStreamPlayer" parent="."]
[node name="Play" type="Button" parent="."] [node name="Play" type="Button" parent="."]
layout_mode = 2 margin_right = 141.0
margin_bottom = 32.0
rect_min_size = Vector2( 128, 32 )
size_flags_vertical = 4 size_flags_vertical = 4
text = "Play" text = "Play"
[node name="Label" type="Label" parent="."] [node name="Label" type="Label" parent="."]
custom_minimum_size = Vector2(500, 0) margin_left = 173.0
layout_mode = 2 margin_right = 473.0
margin_bottom = 31.0
rect_min_size = Vector2( 300, 0 )
text = "A .sfxr file can be used as regular audio files like .wav, .ogg, and .mp3." text = "A .sfxr file can be used as regular audio files like .wav, .ogg, and .mp3."
autowrap_mode = 3 autowrap = true
[node name="PlayFile" type="Button" parent="."] [node name="PlayFile" type="Button" parent="."]
layout_mode = 2 margin_top = 64.0
margin_right = 141.0
margin_bottom = 96.0
rect_min_size = Vector2( 128, 32 )
size_flags_vertical = 4 size_flags_vertical = 4
text = "Load .sfxr File" text = "Load .sfxr File"
[node name="Label2" type="Label" parent="."] [node name="Label2" type="Label" parent="."]
custom_minimum_size = Vector2(500, 0) margin_left = 173.0
layout_mode = 2 margin_top = 64.0
margin_right = 473.0
margin_bottom = 95.0
rect_min_size = Vector2( 300, 0 )
text = "A .sfxr file is a AudioStreamSample resource that can be loaded with load() or preload()." text = "A .sfxr file is a AudioStreamSample resource that can be loaded with load() or preload()."
autowrap_mode = 3 autowrap = true
[node name="Generate" type="Button" parent="."] [node name="Generate" type="Button" parent="."]
layout_mode = 2 margin_top = 144.0
margin_right = 141.0
margin_bottom = 176.0
rect_min_size = Vector2( 128, 32 )
size_flags_vertical = 4 size_flags_vertical = 4
text = "Runtime Generation" text = "Runtime Generation"
[node name="Label3" type="Label" parent="."] [node name="Label3" type="Label" parent="."]
custom_minimum_size = Vector2(500, 0) margin_left = 173.0
layout_mode = 2 margin_top = 128.0
margin_right = 473.0
margin_bottom = 193.0
rect_min_size = Vector2( 300, 0 )
text = "You can generate the sound effect at runtime. However, due to performance constraints with GDScript, your game might freeze when generating long sounds." text = "You can generate the sound effect at runtime. However, due to performance constraints with GDScript, your game might freeze when generating long sounds."
autowrap_mode = 3 autowrap = true
[connection signal="pressed" from="Play" to="." method="_on_Play_pressed"] [connection signal="pressed" from="Play" to="." method="_on_Play_pressed"]
[connection signal="pressed" from="PlayFile" to="." method="_on_PlayFile_pressed"] [connection signal="pressed" from="PlayFile" to="." method="_on_PlayFile_pressed"]

View File

@ -1,14 +1,13 @@
[remap] [remap]
importer="com.timothyqiu.gdfxr.importer" importer="com.timothyqiu.gdfxr.importer"
type="AudioStreamWAV" type="AudioStreamSample"
uid="uid://byf7u7a25fuf4" path="res://.import/example.sfxr-e3731bcdcd8403a2391e92667a5d1076.sample"
path="res://.godot/imported/example.sfxr-e3731bcdcd8403a2391e92667a5d1076.sample"
[deps] [deps]
source_file="res://example/example.sfxr" source_file="res://example/example.sfxr"
dest_files=["res://.godot/imported/example.sfxr-e3731bcdcd8403a2391e92667a5d1076.sample"] dest_files=[ "res://.import/example.sfxr-e3731bcdcd8403a2391e92667a5d1076.sample" ]
[params] [params]

View File

@ -1,9 +1,8 @@
[remap] [remap]
importer="texture" importer="texture"
type="CompressedTexture2D" type="StreamTexture"
uid="uid://b16qnfl6slyy2" path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"
metadata={ metadata={
"vram_texture": false "vram_texture": false
} }
@ -11,24 +10,26 @@ metadata={
[deps] [deps]
source_file="res://icon.png" source_file="res://icon.png"
dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"] dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
[params] [params]
compress/mode=0 compress/mode=0
compress/lossy_quality=0.7 compress/lossy_quality=0.7
compress/hdr_compression=1 compress/hdr_mode=0
compress/bptc_ldr=0 compress/bptc_ldr=0
compress/normal_map=0 compress/normal_map=0
compress/channel_pack=0 flags/repeat=0
mipmaps/generate=false flags/filter=true
mipmaps/limit=-1 flags/mipmaps=false
roughness/mode=0 flags/anisotropic=false
roughness/src_normal="" flags/srgb=2
process/fix_alpha_border=true process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false process/normal_map_invert_y=false
process/hdr_as_srgb=false stream=false
process/hdr_clamp_exposure=false size_limit=0
process/size_limit=0 detect_3d=true
detect_3d/compress_to=1 svg/scale=1.0

View File

@ -6,15 +6,14 @@
; [section] ; section goes between [] ; [section] ; section goes between []
; param=value ; assign values to parameters ; param=value ; assign values to parameters
config_version=5 config_version=4
[application] [application]
config/name="gdfxr" config/name="gdfxr"
run/main_scene="res://example/Example.tscn" run/main_scene="res://example/Example.tscn"
config/features=PackedStringArray("4.0")
config/icon="res://icon.png" config/icon="res://icon.png"
[editor_plugins] [editor_plugins]
enabled=PackedStringArray("res://addons/gdfxr/plugin.cfg") enabled=PoolStringArray( "res://addons/gdfxr/plugin.cfg" )

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 19 KiB