├── icon.ico ├── icon.png ├── splash.png ├── assets ├── fonts │ ├── wqy-MicroHei.ttf │ ├── IBMPlexMono-Bold.ttf │ ├── IBMPlexSans-Light.ttf │ ├── IBMPlexMono-Regular.ttf │ └── IBMPlexSans-Regular.ttf ├── logo.svg.import ├── ic_help.svg.import ├── ic_info.svg.import ├── ic_logo.svg.import ├── ic_loop.svg.import ├── ic_note.svg.import ├── ic_play.svg.import ├── ic_stop.svg.import ├── ic_clear.svg.import ├── ic_folder.svg.import ├── ic_autoplay.svg.import ├── ic_favorite.svg.import ├── ic_unfavorite.svg.import ├── ic_folder_full.svg.import ├── ic_direction_down.svg.import ├── ic_direction_right.svg.import ├── ic_play.svg ├── ic_direction_down.svg ├── ic_direction_right.svg ├── ic_clear.svg ├── ic_folder_full.svg ├── ic_folder.svg ├── ic_autoplay.svg ├── ic_favorite.svg ├── ic_loop.svg ├── ic_logo.svg ├── ic_note.svg ├── ic_stop.svg ├── ic_unfavorite.svg ├── ic_info.svg ├── ic_help.svg ├── logo.svg └── ui_theme.tres ├── locale ├── locales.en.translation ├── locales.csv.import └── locales.csv ├── src ├── InfoPlaylist.gd ├── MessageBox.gd ├── HelpPanel.gd ├── InfoBox.gd ├── AnalizeThread.gd ├── Config.gd ├── ItemContainer.gd ├── Export.gd ├── Main.gd ├── Playback.gd ├── DirectoryBrowser.gd ├── Playlist.gd └── GDScriptAudioImport.gd ├── .gitignore ├── default_env.tres ├── icon.png.import ├── splash.png.import ├── LICENSE ├── project.godot ├── README.md ├── ItemContainer.tscn └── Main.tscn /icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelriot/SFX-Browser/HEAD/icon.ico -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelriot/SFX-Browser/HEAD/icon.png -------------------------------------------------------------------------------- /splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelriot/SFX-Browser/HEAD/splash.png -------------------------------------------------------------------------------- /assets/fonts/wqy-MicroHei.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelriot/SFX-Browser/HEAD/assets/fonts/wqy-MicroHei.ttf -------------------------------------------------------------------------------- /locale/locales.en.translation: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelriot/SFX-Browser/HEAD/locale/locales.en.translation -------------------------------------------------------------------------------- /assets/fonts/IBMPlexMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelriot/SFX-Browser/HEAD/assets/fonts/IBMPlexMono-Bold.ttf -------------------------------------------------------------------------------- /assets/fonts/IBMPlexSans-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelriot/SFX-Browser/HEAD/assets/fonts/IBMPlexSans-Light.ttf -------------------------------------------------------------------------------- /assets/fonts/IBMPlexMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelriot/SFX-Browser/HEAD/assets/fonts/IBMPlexMono-Regular.ttf -------------------------------------------------------------------------------- /assets/fonts/IBMPlexSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelriot/SFX-Browser/HEAD/assets/fonts/IBMPlexSans-Regular.ttf -------------------------------------------------------------------------------- /src/InfoPlaylist.gd: -------------------------------------------------------------------------------- 1 | extends HBoxContainer 2 | """ 3 | InfoPlaylist 4 | """ 5 | 6 | 7 | 8 | 9 | func hide(_path=null) -> void: 10 | .hide() 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Godot-specific ignores 3 | .import/ 4 | export.cfg 5 | export_presets.cfg 6 | exports 7 | 8 | # Mono-specific ignores 9 | .mono/ 10 | data_*/ 11 | -------------------------------------------------------------------------------- /default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | 5 | [resource] 6 | background_mode = 2 7 | background_sky = SubResource( 1 ) 8 | -------------------------------------------------------------------------------- /locale/locales.csv.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="csv_translation" 4 | type="Translation" 5 | 6 | [deps] 7 | 8 | files=[ "res://locale/locales.en.translation" ] 9 | 10 | source_file="res://locale/locales.csv" 11 | dest_files=[ "res://locale/locales.en.translation" ] 12 | 13 | [params] 14 | 15 | compress=true 16 | delimiter=0 17 | -------------------------------------------------------------------------------- /src/MessageBox.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | """ 3 | Message Box 4 | """ 5 | 6 | func _ready() -> void: 7 | modulate.a = 1 8 | hide() 9 | 10 | 11 | func display_message(_text:String, _color:Color=Config.THEME_COLOR_RED) -> void: 12 | modulate.a = 1 13 | show() 14 | get("custom_styles/panel").bg_color = _color 15 | $MarginContainer/HBoxContainer/Label.text = _text 16 | $Timer.start() 17 | 18 | 19 | func _on_Timer_timeout() -> void: 20 | $AnimationPlayer.play("hide") 21 | 22 | 23 | func _on_Close_pressed() -> void: 24 | $Timer.stop() 25 | _on_Timer_timeout() 26 | -------------------------------------------------------------------------------- /src/HelpPanel.gd: -------------------------------------------------------------------------------- 1 | extends PanelContainer 2 | """ 3 | Help Panels 4 | """ 5 | 6 | func _ready() -> void: 7 | for label in $MarginContainer/HBoxContainer.get_children(): 8 | if label is Label: 9 | label.text = tr(label.name.to_upper()) 10 | if Config.CONFIGDATA["main"]["folder_path"]: 11 | hide() 12 | else: 13 | show() 14 | 15 | 16 | func close(_path=null) -> void: 17 | _on_Close_pressed() 18 | 19 | 20 | func _on_Close_pressed() -> void: 21 | $AnimationPlayer.play("hide") 22 | 23 | 24 | func show() -> void: 25 | modulate.a = 1 26 | .show() 27 | 28 | 29 | -------------------------------------------------------------------------------- /locale/locales.csv: -------------------------------------------------------------------------------- 1 | id,en 2 | APP_TITLE,Sample Browser 3 | APP_INFO,Version %s \nDeveloped by Monolith of Minds 4 | LOAD,Library 5 | LOAD_POPUP,Select sample library folder 6 | INFOBROWSER,ctrl + o \n\nStart by selecting which folder you want to rummage through. 7 | INFO0,↑ & ↓ \n\nQuickly move though your library. 8 | INFO1,Space or LMB \n\nPlay the selected sample. \nRMB to Stop playback. 9 | INFO2,F \n\nMark the selected sample as a favourite. 10 | INFO3,abc... \n\nEnter a new name for the sample after export. 11 | CLEAR,clear all 12 | EXPORT,Export 13 | EXPORT_POPUP,Select export directory 14 | NO_EXPORT_FILES,"Nothing to export. Enter new export file names for the files you wish to export." 15 | EXPORT_INFO,%s file(s) exported to %s 16 | -------------------------------------------------------------------------------- /icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icon.png" 13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /splash.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/splash.png-929ed8a00b89ba36c51789452f874c77.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://splash.png" 13 | dest_files=[ "res://.import/splash.png-929ed8a00b89ba36c51789452f874c77.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/logo.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/logo.svg-01597fe4b7eb446be26a49e8a22b6f42.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/logo.svg" 13 | dest_files=[ "res://.import/logo.svg-01597fe4b7eb446be26a49e8a22b6f42.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /src/InfoBox.gd: -------------------------------------------------------------------------------- 1 | extends PanelContainer 2 | """ 3 | Info Box 4 | """ 5 | 6 | func _ready() -> void: 7 | var version = ProjectSettings["application/config/version"] 8 | var _text = "" 9 | _text += tr("APP_INFO") % [version] + "\n" 10 | _text += "[url=https://github.com/pixelriot/SFX-Browser]" + "Visit us on Github" + "[/url]" + "\n" 11 | 12 | $MarginContainer/HBoxContainer/RichTextLabel.bbcode_enabled = true 13 | $MarginContainer/HBoxContainer/RichTextLabel.bbcode_text = _text 14 | hide() 15 | 16 | 17 | func close(_path=null) -> void: 18 | _on_Close_pressed() 19 | 20 | 21 | func _on_Close_pressed() -> void: 22 | $AnimationPlayer.play("hide") 23 | 24 | 25 | func show() -> void: 26 | modulate.a = 1 27 | .show() 28 | 29 | 30 | func _on_RichTextLabel_meta_clicked(meta) -> void: 31 | OS.shell_open(meta) 32 | -------------------------------------------------------------------------------- /assets/ic_help.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_help.svg-457a991545389554bc9c59bbb421cb7a.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_help.svg" 13 | dest_files=[ "res://.import/ic_help.svg-457a991545389554bc9c59bbb421cb7a.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_info.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_info.svg-59f7ced217781e851eabc5db1d7034f0.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_info.svg" 13 | dest_files=[ "res://.import/ic_info.svg-59f7ced217781e851eabc5db1d7034f0.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_logo.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_logo.svg-778a3f21ae113f22fce2622c6527dad3.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_logo.svg" 13 | dest_files=[ "res://.import/ic_logo.svg-778a3f21ae113f22fce2622c6527dad3.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_loop.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_loop.svg-932d7f8438d3b65cbabfb484d9b292ea.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_loop.svg" 13 | dest_files=[ "res://.import/ic_loop.svg-932d7f8438d3b65cbabfb484d9b292ea.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_note.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_note.svg-d6678e311e88a8f00f7cad7d7a71a6b0.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_note.svg" 13 | dest_files=[ "res://.import/ic_note.svg-d6678e311e88a8f00f7cad7d7a71a6b0.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_play.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_play.svg-196841356150a3abc9cf15fb31332047.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_play.svg" 13 | dest_files=[ "res://.import/ic_play.svg-196841356150a3abc9cf15fb31332047.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_stop.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_stop.svg-f8cd9033b2d74858b28c6479ed337622.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_stop.svg" 13 | dest_files=[ "res://.import/ic_stop.svg-f8cd9033b2d74858b28c6479ed337622.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_clear.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_clear.svg-4a1d07859e0d5848b82a7e3890c2e13d.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_clear.svg" 13 | dest_files=[ "res://.import/ic_clear.svg-4a1d07859e0d5848b82a7e3890c2e13d.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_folder.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_folder.svg-b838b4ed680d0e6fa39987f926b50064.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_folder.svg" 13 | dest_files=[ "res://.import/ic_folder.svg-b838b4ed680d0e6fa39987f926b50064.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_autoplay.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_autoplay.svg-ed81d88702bff6f65acd8b235bd84f9f.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_autoplay.svg" 13 | dest_files=[ "res://.import/ic_autoplay.svg-ed81d88702bff6f65acd8b235bd84f9f.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_favorite.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_favorite.svg-ce5fb6048012041e169142b1e623e428.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_favorite.svg" 13 | dest_files=[ "res://.import/ic_favorite.svg-ce5fb6048012041e169142b1e623e428.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /src/AnalizeThread.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | """ 3 | Analyze Audio Samples 4 | """ 5 | var analysis_finished = false 6 | var _thread 7 | var lengths = [] 8 | 9 | func analyze_files(file_paths=[]) -> void: 10 | if _thread: 11 | var _t = _thread.wait_to_finish() 12 | _thread = Thread.new() 13 | _thread.start(self, "_analyze", file_paths) 14 | 15 | 16 | func _analyze(file_paths=[]) -> void: 17 | print("analysis files ...") 18 | analysis_finished = false 19 | lengths.clear() 20 | for path in file_paths: 21 | var stream = AudioImport.loadfile(path) 22 | if stream: 23 | lengths.append(stream.get_length()) 24 | analysis_finished = true 25 | print("... finished") 26 | 27 | 28 | func get_data()-> Array: 29 | analysis_finished = false 30 | return lengths 31 | 32 | 33 | func _exit_tree(): 34 | if _thread: 35 | _thread.wait_to_finish() 36 | -------------------------------------------------------------------------------- /assets/ic_unfavorite.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_unfavorite.svg-22c180c87ef3a149adc9109a0b702d10.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_unfavorite.svg" 13 | dest_files=[ "res://.import/ic_unfavorite.svg-22c180c87ef3a149adc9109a0b702d10.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_folder_full.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_folder_full.svg-fcffcebf1440bd37abba92cf4bb8dba0.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_folder_full.svg" 13 | dest_files=[ "res://.import/ic_folder_full.svg-fcffcebf1440bd37abba92cf4bb8dba0.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_direction_down.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_direction_down.svg-83c1c1233d3a77e3c442e1e4b800a676.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_direction_down.svg" 13 | dest_files=[ "res://.import/ic_direction_down.svg-83c1c1233d3a77e3c442e1e4b800a676.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /assets/ic_direction_right.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/ic_direction_right.svg-7f1d9c03e219f0d81f7a3550decd8c95.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/ic_direction_right.svg" 13 | dest_files=[ "res://.import/ic_direction_right.svg-7f1d9c03e219f0d81f7a3550decd8c95.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Richi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/ic_play.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /src/Config.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | """ 3 | Config 4 | """ 5 | var CONFIG_PATH = OS.get_user_data_dir() + "/config.cfg" 6 | var CONFIGDATA = { "main":{ 7 | "folder_path": "", 8 | "export_path": "" 9 | }} 10 | var FAVOURITES = [] 11 | 12 | const THEME_COLOR_GREEN = Color("ceeac7") 13 | const THEME_COLOR_BLUE = Color("bbd2d1") 14 | const THEME_COLOR_RED = Color("d67788") 15 | const THEME_COLOR_BG = Color("464655") 16 | 17 | 18 | func _init() -> void: 19 | print("SFX Browser starting") 20 | print("OS \t" + OS.get_name()) 21 | connect("tree_exiting", self, "save_config") 22 | load_config() 23 | 24 | 25 | func load_config() -> void: 26 | var c = ConfigFile.new() 27 | var err = c.load(CONFIG_PATH) 28 | if err == OK: 29 | for i in CONFIGDATA: 30 | print("" + str(i)) 31 | for j in CONFIGDATA[i]: 32 | if c.has_section_key(i, j): 33 | CONFIGDATA[i][j] = c.get_value(i, j) 34 | print("--" + str(j) + " = " + str(CONFIGDATA[i][j])) 35 | FAVOURITES = c.get_value("main", "favourites", []) 36 | 37 | 38 | func save_config(): 39 | CONFIGDATA["main"]["favourites"] = FAVOURITES 40 | 41 | var c = ConfigFile.new() 42 | c.load(CONFIG_PATH) 43 | for i in CONFIGDATA: 44 | for j in CONFIGDATA[i]: 45 | c.set_value(i, j, CONFIGDATA[i][j]) 46 | c.save(CONFIG_PATH) 47 | 48 | 49 | -------------------------------------------------------------------------------- /assets/ic_direction_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_direction_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_clear.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_folder_full.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_autoplay.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_favorite.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_loop.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /src/ItemContainer.gd: -------------------------------------------------------------------------------- 1 | extends HBoxContainer 2 | """ 3 | Item Container 4 | """ 5 | var file_path : String 6 | 7 | func set_data(idx:String, _file_path:String) -> void: 8 | file_path = _file_path 9 | $Idx.text = idx 10 | $File.text = file_path.get_file() 11 | $File.hint_tooltip = _file_path 12 | if file_path in Config.FAVOURITES: 13 | $Favourite.pressed = true 14 | unfocus() 15 | 16 | 17 | func set_additional_data(length:float) -> void: 18 | var minutes = int(length)/60 19 | if minutes > 0: 20 | var seconds = length - minutes * 60 21 | $Length.text = ( str(minutes) + ":" + str(seconds).pad_decimals(2) ) 22 | else: 23 | $Length.text = ( str(length).pad_decimals(2) ) 24 | 25 | 26 | func get_file_path() -> String: 27 | return file_path 28 | 29 | 30 | func get_export_name() -> String: 31 | return $ExportName.text 32 | 33 | 34 | func clear_export() -> void: 35 | $ExportName.text = "" 36 | 37 | 38 | func _on_ItemContainer_focus_entered() -> void: 39 | modulate.a = 1 40 | $Icon.modulate.a = 1 41 | 42 | 43 | func unfocus() -> void: 44 | modulate.a = 0.9 45 | $Icon.modulate.a = 0 46 | 47 | 48 | func _on_Favourite_toggled(button_pressed: bool) -> void: 49 | if button_pressed: 50 | if not file_path in Config.FAVOURITES: 51 | Config.FAVOURITES.append(file_path) 52 | else: 53 | if file_path in Config.FAVOURITES: 54 | Config.FAVOURITES.erase(file_path) 55 | 56 | 57 | func toggle_favourite() -> void: 58 | $Favourite.pressed = not $Favourite.pressed 59 | 60 | 61 | -------------------------------------------------------------------------------- /assets/ic_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_note.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /src/Export.gd: -------------------------------------------------------------------------------- 1 | extends HBoxContainer 2 | """ 3 | Export 4 | """ 5 | signal export_files(path) 6 | signal display_message(message) 7 | signal clear_export 8 | onready var Export := $Export 9 | onready var FolderPath := $FolderPath 10 | onready var FileDialog := $FileDialog 11 | var export_path : String 12 | 13 | func _ready() -> void: 14 | $Clear.text = tr("CLEAR") 15 | Export.text = tr("EXPORT") 16 | 17 | if Config.CONFIGDATA["main"]["export_path"]: 18 | export_path = Config.CONFIGDATA["main"]["export_path"] 19 | FolderPath.text = export_path 20 | 21 | 22 | func _on_Clear_pressed() -> void: 23 | emit_signal("clear_export") 24 | 25 | 26 | func _on_ExportPath_pressed() -> void: 27 | FileDialog.window_title = tr("EXPORT_POPUP") 28 | var popup_size = Vector2(800, 400) 29 | var popup_position = OS.window_size/2 - popup_size/2 30 | FileDialog.popup(Rect2(popup_position, popup_size)) 31 | 32 | 33 | func _on_FileDialog_dir_selected(dir: String) -> void: 34 | export_path = dir 35 | FolderPath.text = export_path 36 | Config.CONFIGDATA["main"]["export_path"] = export_path 37 | Config.save_config() 38 | 39 | 40 | func _on_Export_pressed(): 41 | if export_path == "": 42 | _on_ExportPath_pressed() 43 | else: 44 | emit_signal("export_files", export_path) 45 | 46 | 47 | func export_finished(amount:int) -> void: 48 | if amount == 0: 49 | emit_signal("display_message", tr("NO_EXPORT_FILES")) 50 | else: 51 | emit_signal("display_message", tr("EXPORT_INFO") % [str(amount), export_path], Config.THEME_COLOR_GREEN) 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/Main.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | """ 3 | Godot audio sample manager 4 | """ 5 | onready var DirectoryBrowser := $PanelContainer/MarginContainer/DirectoryBrowser 6 | onready var Playback := $MarginContainer/Workbench/Playback 7 | onready var Playlist := $MarginContainer/Workbench/Playlist 8 | onready var Export := $MarginContainer/Workbench/Export 9 | onready var BrowserHelp := $PanelContainer/MarginContainer/DirectoryBrowser/BrowserHelp 10 | onready var PlaybackHelp := $MarginContainer/Workbench/PlaybackHelp 11 | onready var InfoBox := $MarginContainer/Workbench/InfoBox 12 | onready var MessageBox := $MarginContainer/Workbench/MessageBox 13 | 14 | func _ready() -> void: 15 | VisualServer.set_default_clear_color(Config.THEME_COLOR_BG) 16 | 17 | DirectoryBrowser.connect("directory_changed", Playlist, "load_files_from_folder") 18 | DirectoryBrowser.connect("directory_changed", Playback, "directory_changed") 19 | DirectoryBrowser.connect("directory_changed", PlaybackHelp, "close") 20 | 21 | Playback.connect("show_help", BrowserHelp, "show") 22 | Playback.connect("show_help", PlaybackHelp, "show") 23 | Playback.connect("show_info", InfoBox, "show") 24 | 25 | Playlist.connect("play_audio", Playback, "play_audio") 26 | Playlist.connect("stop_audio", Playback, "stop_audio") 27 | Playlist.connect("export_finished", Export, "export_finished") 28 | 29 | Export.connect("export_files", Playlist, "export_files") 30 | Export.connect("clear_export", Playlist, "clear_export") 31 | Export.connect("display_message", MessageBox, "display_message") 32 | 33 | 34 | -------------------------------------------------------------------------------- /project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | [application] 12 | 13 | config/name="SFX Browser" 14 | run/main_scene="res://Main.tscn" 15 | boot_splash/image="res://splash.png" 16 | config/icon="res://icon.png" 17 | config/windows_native_icon="res://icon.ico" 18 | config/version="0.9.3" 19 | 20 | [autoload] 21 | 22 | Config="*res://src/Config.gd" 23 | AudioImport="*res://src/GDScriptAudioImport.gd" 24 | 25 | [input] 26 | 27 | ui_accept={ 28 | "deadzone": 0.5, 29 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777221,"unicode":0,"echo":false,"script":null) 30 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777222,"unicode":0,"echo":false,"script":null) 31 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null) 32 | ] 33 | } 34 | 35 | [locale] 36 | 37 | translations=PoolStringArray( "res://locale/locales.en.translation" ) 38 | 39 | [rendering] 40 | 41 | environment/default_environment="res://default_env.tres" 42 | -------------------------------------------------------------------------------- /assets/ic_stop.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_unfavorite.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SFX Browser 2 | 3 | SFX Browser is a fast and simple utility to browse through vast audio libraries and extract only the tracks you need. You can scan multiple sample folders, quickly navigate and listen to the track-lists, like, rename, and export what you need to a new folder. 4 | 5 | ![img](https://user-images.githubusercontent.com/21098503/123825223-05c52b80-d8ff-11eb-83f7-5dc0dbd224e1.png) 6 | 7 | ## Features 8 | - Scan any folder for audio files 9 | - Quickly navigate and play the track-list via arrow keys 10 | - Mark favorites 11 | - Rename the sample you want to extract 12 | - Export all selected tracks into a clean new folder 13 | 14 | 15 | https://user-images.githubusercontent.com/21098503/124129058-af322b80-da7d-11eb-94e0-b44edf688c25.mp4 16 | 17 | SFX Browser works great when picking the right sounds for your video game or software project, or just to rename a poorly labeled library. 18 | 19 | SFX Browser is build with the [Godot engine](https://github.com/godotengine/godot), runs under Windows, Max OS and Linux and uses Giannino Clemente's awesome [GDScriptAudioImport](https://github.com/Gianclgar/GDScriptAudioImport) for audio file processing. It’s free and open source for everybody to download, change and contribute to the project as one pleases. 20 | 21 | --- 22 | 23 | SFX Browser is developed by [Monolith of Minds](https://monolithofminds.com/) and you. Let us know what we can improve, or jump right in and contribute. 24 | 25 | We make video games. If you feel like supporting us, consider buying [Resolutiion](https://monolithofminds.com/resolutiion.html) or visit our latest project: [Lila’s Sky Ark](https://monolithofminds.com/lilasskyark.html). 26 | Thank you. 27 | -------------------------------------------------------------------------------- /assets/ic_info.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /assets/ic_help.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 39 | -------------------------------------------------------------------------------- /src/Playback.gd: -------------------------------------------------------------------------------- 1 | extends HBoxContainer 2 | """ 3 | Playback 4 | """ 5 | signal show_help 6 | signal show_info 7 | var is_looping = false 8 | onready var AudioPlayer := $AudioStreamPlayer 9 | 10 | 11 | func _on_Play_pressed() -> void: 12 | if AudioPlayer.playing: 13 | AudioPlayer.stop() 14 | elif AudioPlayer.stream: 15 | AudioPlayer.play() 16 | set_play_icon() 17 | 18 | 19 | func _on_Loop_toggled(button_pressed: bool) -> void: 20 | is_looping = button_pressed 21 | 22 | if AudioPlayer.playing: 23 | AudioPlayer.stop() 24 | if (AudioPlayer.stream is AudioStreamOGGVorbis 25 | or AudioPlayer.stream is AudioStreamMP3): 26 | AudioPlayer.stream.loop = button_pressed 27 | elif AudioPlayer.stream is AudioStreamSample: 28 | AudioPlayer.stream.loop_mode = 1 if button_pressed else 0 29 | AudioPlayer.play() 30 | 31 | 32 | func _on_Info_pressed() -> void: 33 | emit_signal("show_info") 34 | 35 | 36 | func _on_Help_pressed() -> void: 37 | emit_signal("show_help") 38 | 39 | 40 | func _on_AudioStreamPlayer_finished() -> void: 41 | set_play_icon() 42 | 43 | 44 | func play_audio(file_path:String="") -> void: 45 | if file_path: 46 | var stream = AudioImport.loadfile(file_path, is_looping) 47 | 48 | # var new_path = copy_file_to_user_folder(file_path) 49 | # yield(get_tree(), "idle_frame") 50 | # yield(get_tree(), "idle_frame") 51 | # yield(get_tree(), "idle_frame") 52 | # var s = load(new_path) 53 | # var stream = s 54 | 55 | if stream: 56 | AudioPlayer.stream = stream 57 | AudioPlayer.play() 58 | set_play_icon() 59 | 60 | 61 | #func copy_file_to_user_folder(file_path:String="") -> String: 62 | # var dir = Directory.new() 63 | # var new_file_name = OS.get_user_data_dir() + "/" + file_path.get_file() 64 | # dir.copy(file_path, new_file_name) 65 | # return new_file_name 66 | 67 | 68 | func stop_audio() -> void: 69 | AudioPlayer.stop() 70 | set_play_icon() 71 | 72 | 73 | func set_play_icon() -> void: 74 | if AudioPlayer.playing: 75 | $Play.icon = load("res://assets/ic_stop.svg") 76 | elif AudioPlayer.stream: 77 | $Play.icon = load("res://assets/ic_autoplay.svg") 78 | 79 | 80 | func directory_changed(_folder_path:String) -> void: 81 | AudioPlayer.stop() 82 | AudioPlayer.stream = null 83 | set_play_icon() 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 14 | 16 | 34 | 38 | 42 | 46 | 50 | 54 | 58 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/DirectoryBrowser.gd: -------------------------------------------------------------------------------- 1 | extends VBoxContainer 2 | """ 3 | Directory Browser 4 | """ 5 | signal directory_changed(new_directory) 6 | var current_directory : String 7 | onready var Tree := $Tree 8 | onready var FileDialog := $FileDialog 9 | onready var BrowserHelp := $BrowserHelp 10 | 11 | func _ready() -> void: 12 | $Load.text = tr("LOAD") 13 | 14 | yield(get_tree().current_scene, "ready") 15 | if Config.CONFIGDATA["main"]["folder_path"]: 16 | Tree.show() 17 | BrowserHelp.hide() 18 | current_directory = Config.CONFIGDATA["main"]["folder_path"] 19 | add_tree_items(current_directory) 20 | emit_signal("directory_changed", current_directory) 21 | else: 22 | Tree.hide() 23 | 24 | 25 | func _on_FileDialog_dir_selected(dir: String) -> void: 26 | Tree.show() 27 | BrowserHelp.hide() 28 | current_directory = dir 29 | Tree.clear() 30 | add_tree_items(dir) 31 | 32 | Config.CONFIGDATA["main"]["folder_path"] = current_directory 33 | Config.save_config() 34 | emit_signal("directory_changed", current_directory) 35 | 36 | 37 | func _on_Load_pressed(): 38 | FileDialog.current_dir = current_directory 39 | FileDialog.window_title = tr("LOAD_POPUP") 40 | var popup_size = Vector2(800, 400) 41 | var popup_position = OS.window_size/2 - popup_size/2 42 | FileDialog.popup(Rect2(popup_position, popup_size)) 43 | 44 | 45 | func _on_Tree_item_selected() -> void: 46 | var item = Tree.get_selected() 47 | var path = current_directory + item.get_meta("path_in_tree") 48 | emit_signal("directory_changed", path) 49 | call_deferred("add_tree_items", path, item) 50 | 51 | 52 | func add_tree_items(path:String, _root=null) -> void: 53 | var files = get_subdirectories(path.replace("//", "/")) 54 | var path_in_tree : String 55 | if not _root: 56 | _root = Tree.create_item() 57 | else: 58 | path_in_tree = _root.get_meta("path_in_tree") 59 | 60 | var item_children = get_tree_item_children(_root) 61 | for i in files: 62 | if i in item_children: 63 | continue 64 | var item = Tree.create_item(_root) 65 | item.set_text(0, i) 66 | item.set_meta("path_in_tree", path_in_tree + "/" + i) 67 | 68 | 69 | func get_tree_item_children(root:TreeItem) -> Array: 70 | var item_children = [] 71 | var ti = root.get_children() 72 | while ti: 73 | item_children.append(ti.get_text(0)) 74 | ti = ti.get_next() 75 | return item_children 76 | 77 | 78 | func get_subdirectories(path:String) -> Array: 79 | var directories = [] 80 | 81 | var dir = Directory.new() 82 | if dir.open(path) == OK: 83 | dir.list_dir_begin() 84 | var file_name = dir.get_next() 85 | while file_name != "": 86 | if (dir.current_is_dir() 87 | and not file_name.begins_with(".")): 88 | directories.append(file_name) 89 | file_name = dir.get_next() 90 | dir.list_dir_end() 91 | 92 | directories.sort() 93 | return directories 94 | 95 | -------------------------------------------------------------------------------- /src/Playlist.gd: -------------------------------------------------------------------------------- 1 | extends ScrollContainer 2 | """ 3 | Playlist 4 | """ 5 | signal play_audio(file_path) 6 | signal stop_audio() 7 | signal export_finished(amount) 8 | var file_list = [] 9 | var current_item = null 10 | const ITEM = preload("res://ItemContainer.tscn") 11 | onready var List = $VBoxContainer 12 | onready var AnalizeThread = $AnalizeThread 13 | 14 | func _ready() -> void: 15 | set_process(false) 16 | 17 | 18 | func _unhandled_key_input(event: InputEventKey) -> void: 19 | if event.scancode == KEY_F and event.pressed and not event.is_echo(): 20 | if current_item: 21 | current_item.toggle_favourite() 22 | 23 | 24 | func _process(_delta: float) -> void: 25 | if AnalizeThread.analysis_finished: 26 | set_process(false) 27 | var data = AnalizeThread.get_data() 28 | for i in List.get_child_count(): 29 | List.get_child(i).set_additional_data(data[i]) 30 | 31 | 32 | func load_files_from_folder(_folder_path:String) -> void: 33 | current_item = null 34 | file_list.clear() 35 | file_list = _get_files_from_directory(_folder_path) 36 | 37 | #clear list 38 | for i in List.get_children(): 39 | i.queue_free() 40 | 41 | #create new list items 42 | var index_size = str(file_list.size()).length() 43 | for j in file_list.size(): 44 | var item = ITEM.instance() 45 | item.set_data(str(j).pad_zeros(index_size), file_list[j]) 46 | List.add_child(item) 47 | item.connect("focus_entered", self, "_on_item_selected", [item]) 48 | item.connect("gui_input", self, "_on_item_input", [item]) 49 | 50 | scroll_vertical = 0 51 | 52 | #start analyze thread 53 | AnalizeThread.call_deferred("analyze_files", file_list) 54 | set_process(true) 55 | 56 | 57 | func _get_files_from_directory(_folder_path:String) -> Array: 58 | var _file_list = [] 59 | var d = Directory.new() 60 | d.open(_folder_path) 61 | d.list_dir_begin() 62 | var f = d.get_next() 63 | while (f != ""): 64 | if f.get_extension() in ["wav", "ogg", "mp3"]: 65 | _file_list.append(_folder_path + "/" + f) 66 | f = d.get_next() 67 | d.list_dir_end() 68 | 69 | _file_list.sort() 70 | return _file_list 71 | 72 | 73 | func _on_item_selected(item) -> void: 74 | if current_item: 75 | current_item.unfocus() 76 | current_item = item 77 | #playback is handled in Playback node 78 | emit_signal("play_audio", item.get_file_path()) 79 | 80 | 81 | func _on_item_input(event:InputEvent, item:Control) -> void: 82 | if event is InputEventMouseButton and event.pressed and not event.is_echo(): 83 | if item == current_item: 84 | if event.button_index == BUTTON_LEFT: 85 | #restart playback 86 | emit_signal("play_audio", item.get_file_path()) 87 | elif event.button_index == BUTTON_RIGHT: 88 | #stop playback 89 | emit_signal("stop_audio") 90 | 91 | 92 | func clear_export() -> void: 93 | for i in List.get_children(): 94 | if i.get_export_name() != "": 95 | i.clear_export() 96 | 97 | 98 | func export_files(export_dir:String) -> void: 99 | var dir = Directory.new() 100 | var amount = 0 101 | for i in List.get_children(): 102 | var export_name = i.get_export_name() 103 | if export_name: 104 | var extention = i.get_file_path().get_extension() 105 | dir.copy(i.get_file_path(), export_dir + "/" + export_name + "." + extention) 106 | amount += 1 107 | emit_signal("export_finished", amount) 108 | 109 | -------------------------------------------------------------------------------- /ItemContainer.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=9 format=2] 2 | 3 | [ext_resource path="res://src/ItemContainer.gd" type="Script" id=1] 4 | [ext_resource path="res://assets/ic_note.svg" type="Texture" id=2] 5 | [ext_resource path="res://assets/ui_theme.tres" type="Theme" id=3] 6 | [ext_resource path="res://assets/ic_favorite.svg" type="Texture" id=4] 7 | [ext_resource path="res://assets/ic_unfavorite.svg" type="Texture" id=5] 8 | [ext_resource path="res://assets/ic_clear.svg" type="Texture" id=6] 9 | [ext_resource path="res://assets/fonts/IBMPlexMono-Regular.ttf" type="DynamicFontData" id=7] 10 | 11 | [sub_resource type="DynamicFont" id=1] 12 | size = 14 13 | font_data = ExtResource( 7 ) 14 | 15 | [node name="ItemContainer" type="HBoxContainer"] 16 | anchor_right = 1.0 17 | anchor_bottom = 1.0 18 | margin_right = -144.0 19 | margin_bottom = -576.0 20 | rect_min_size = Vector2( 0, 30 ) 21 | focus_mode = 2 22 | mouse_filter = 0 23 | size_flags_horizontal = 7 24 | theme = ExtResource( 3 ) 25 | custom_constants/separation = 10 26 | script = ExtResource( 1 ) 27 | __meta__ = { 28 | "_edit_use_anchors_": false 29 | } 30 | 31 | [node name="Icon" type="TextureRect" parent="."] 32 | modulate = Color( 0.807843, 0.917647, 0.780392, 1 ) 33 | margin_right = 24.0 34 | margin_bottom = 30.0 35 | texture = ExtResource( 2 ) 36 | stretch_mode = 4 37 | 38 | [node name="Idx" type="Label" parent="."] 39 | margin_left = 34.0 40 | margin_right = 58.0 41 | margin_bottom = 30.0 42 | size_flags_vertical = 5 43 | custom_fonts/font = SubResource( 1 ) 44 | text = "idx" 45 | align = 2 46 | valign = 1 47 | 48 | [node name="File" type="Label" parent="."] 49 | margin_left = 68.0 50 | margin_right = 508.0 51 | margin_bottom = 30.0 52 | mouse_filter = 1 53 | size_flags_horizontal = 15 54 | size_flags_vertical = 3 55 | text = "filename" 56 | valign = 1 57 | clip_text = true 58 | 59 | [node name="VSeparator" type="VSeparator" parent="."] 60 | margin_left = 518.0 61 | margin_right = 538.0 62 | margin_bottom = 30.0 63 | custom_constants/separation = 20 64 | 65 | [node name="Length" type="Label" parent="."] 66 | margin_left = 548.0 67 | margin_right = 580.0 68 | margin_bottom = 30.0 69 | rect_min_size = Vector2( 20, 0 ) 70 | size_flags_vertical = 3 71 | custom_fonts/font = SubResource( 1 ) 72 | text = "-:--" 73 | valign = 1 74 | 75 | [node name="VSeparator2" type="VSeparator" parent="."] 76 | margin_left = 590.0 77 | margin_right = 610.0 78 | margin_bottom = 30.0 79 | custom_constants/separation = 20 80 | 81 | [node name="Favourite" type="TextureButton" parent="."] 82 | modulate = Color( 0.839216, 0.466667, 0.533333, 1 ) 83 | margin_left = 620.0 84 | margin_right = 650.0 85 | margin_bottom = 30.0 86 | rect_min_size = Vector2( 30, 0 ) 87 | toggle_mode = true 88 | texture_normal = ExtResource( 5 ) 89 | texture_pressed = ExtResource( 4 ) 90 | texture_hover = ExtResource( 5 ) 91 | texture_disabled = ExtResource( 5 ) 92 | texture_focused = ExtResource( 5 ) 93 | expand = true 94 | stretch_mode = 3 95 | 96 | [node name="ExportName" type="LineEdit" parent="."] 97 | margin_left = 660.0 98 | margin_right = 860.0 99 | margin_bottom = 26.0 100 | rect_min_size = Vector2( 200, 0 ) 101 | size_flags_horizontal = 13 102 | size_flags_vertical = 0 103 | custom_icons/clear = ExtResource( 6 ) 104 | clear_button_enabled = true 105 | placeholder_text = "export file name" 106 | placeholder_alpha = 0.25 107 | 108 | [node name="VSeparator3" type="VSeparator" parent="."] 109 | margin_left = 870.0 110 | margin_right = 880.0 111 | margin_bottom = 30.0 112 | custom_constants/separation = 10 113 | 114 | [connection signal="focus_entered" from="." to="." method="_on_ItemContainer_focus_entered"] 115 | [connection signal="toggled" from="Favourite" to="." method="_on_Favourite_toggled"] 116 | -------------------------------------------------------------------------------- /assets/ui_theme.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Theme" load_steps=28 format=2] 2 | 3 | [ext_resource path="res://assets/fonts/IBMPlexMono-Regular.ttf" type="DynamicFontData" id=1] 4 | [ext_resource path="res://assets/fonts/IBMPlexSans-Regular.ttf" type="DynamicFontData" id=2] 5 | [ext_resource path="res://assets/ic_direction_right.svg" type="Texture" id=3] 6 | [ext_resource path="res://assets/ic_direction_down.svg" type="Texture" id=4] 7 | [ext_resource path="res://assets/ic_clear.svg" type="Texture" id=5] 8 | [ext_resource path="res://assets/fonts/wqy-MicroHei.ttf" type="DynamicFontData" id=6] 9 | 10 | [sub_resource type="DynamicFont" id=1] 11 | size = 18 12 | font_data = ExtResource( 1 ) 13 | 14 | [sub_resource type="StyleBoxEmpty" id=2] 15 | 16 | [sub_resource type="StyleBoxFlat" id=3] 17 | bg_color = Color( 0.180392, 0.14902, 0.2, 0 ) 18 | border_color = Color( 0.937255, 1, 0.803922, 1 ) 19 | 20 | [sub_resource type="StyleBoxFlat" id=4] 21 | bg_color = Color( 0.180392, 0.14902, 0.2, 0 ) 22 | border_width_bottom = 1 23 | border_color = Color( 0.937255, 1, 0.803922, 0 ) 24 | 25 | [sub_resource type="StyleBoxFlat" id=5] 26 | bg_color = Color( 0.807843, 0.917647, 0.780392, 1 ) 27 | 28 | [sub_resource type="StyleBoxFlat" id=6] 29 | 30 | [sub_resource type="StyleBoxEmpty" id=7] 31 | 32 | [sub_resource type="StyleBoxFlat" id=8] 33 | bg_color = Color( 0.6, 0.6, 0.6, 0 ) 34 | border_width_bottom = 2 35 | border_color = Color( 0.215686, 0.215686, 0.27451, 1 ) 36 | 37 | [sub_resource type="StyleBoxFlat" id=9] 38 | bg_color = Color( 0.215686, 0.215686, 0.27451, 1 ) 39 | 40 | [sub_resource type="StyleBoxFlat" id=10] 41 | bg_color = Color( 0.27451, 0.27451, 0.333333, 1 ) 42 | 43 | [sub_resource type="StyleBoxEmpty" id=11] 44 | 45 | [sub_resource type="StyleBoxEmpty" id=12] 46 | 47 | [sub_resource type="StyleBoxEmpty" id=13] 48 | 49 | [sub_resource type="StyleBoxEmpty" id=14] 50 | 51 | [sub_resource type="StyleBoxFlat" id=15] 52 | bg_color = Color( 0.733333, 0.823529, 0.819608, 1 ) 53 | 54 | [sub_resource type="StyleBoxFlat" id=16] 55 | bg_color = Color( 0.807843, 0.917647, 0.780392, 1 ) 56 | 57 | [sub_resource type="StyleBoxFlat" id=17] 58 | 59 | [sub_resource type="StyleBoxLine" id=18] 60 | color = Color( 0.215686, 0.215686, 0.27451, 1 ) 61 | thickness = 4 62 | vertical = true 63 | 64 | [sub_resource type="StyleBoxEmpty" id=19] 65 | 66 | [sub_resource type="StyleBoxFlat" id=20] 67 | bg_color = Color( 0.27451, 0.27451, 0.333333, 1 ) 68 | border_width_left = 2 69 | border_width_top = 2 70 | border_width_right = 2 71 | border_width_bottom = 2 72 | border_color = Color( 0.733333, 0.823529, 0.819608, 1 ) 73 | expand_margin_right = 9.0 74 | expand_margin_top = 24.0 75 | 76 | [sub_resource type="DynamicFont" id=21] 77 | size = 18 78 | font_data = ExtResource( 2 ) 79 | fallback/0 = ExtResource( 6 ) 80 | 81 | [resource] 82 | default_font = SubResource( 21 ) 83 | Button/colors/font_color = Color( 0.733333, 0.823529, 0.819608, 1 ) 84 | Button/colors/font_color_disabled = Color( 0.45098, 0.45098, 0.509804, 1 ) 85 | Button/colors/font_color_hover = Color( 0.807843, 0.917647, 0.780392, 1 ) 86 | Button/colors/font_color_pressed = Color( 0.215686, 0.215686, 0.27451, 1 ) 87 | Button/constants/hseparation = 15 88 | Button/fonts/font = SubResource( 1 ) 89 | Button/styles/disabled = SubResource( 2 ) 90 | Button/styles/focus = SubResource( 3 ) 91 | Button/styles/hover = SubResource( 3 ) 92 | Button/styles/normal = SubResource( 4 ) 93 | Button/styles/pressed = SubResource( 5 ) 94 | Dialogs/constants/button_margin = 32 95 | Dialogs/constants/margin = 8 96 | FileDialog/colors/file_icon_modulate = Color( 1, 1, 1, 1 ) 97 | FileDialog/colors/files_disabled = Color( 0, 0, 0, 0.784314 ) 98 | FileDialog/colors/folder_icon_modulate = Color( 1, 1, 1, 1 ) 99 | FileDialog/icons/file = null 100 | FileDialog/icons/folder = null 101 | FileDialog/icons/parent_folder = null 102 | FileDialog/icons/reload = null 103 | FileDialog/icons/toggle_hidden = null 104 | HSeparator/constants/separation = 10 105 | HSeparator/styles/separator = SubResource( 6 ) 106 | Label/colors/font_color = Color( 0.733333, 0.823529, 0.819608, 1 ) 107 | Label/colors/font_color_shadow = Color( 0, 0, 0, 0 ) 108 | Label/colors/font_outline_modulate = Color( 1, 1, 1, 1 ) 109 | Label/constants/line_spacing = 3 110 | Label/constants/shadow_as_outline = 0 111 | Label/constants/shadow_offset_x = 1 112 | Label/constants/shadow_offset_y = 1 113 | Label/fonts/font = null 114 | Label/styles/normal = null 115 | LineEdit/colors/clear_button_color = Color( 0.733333, 0.823529, 0.819608, 1 ) 116 | LineEdit/colors/clear_button_color_pressed = Color( 0.807843, 0.917647, 0.780392, 1 ) 117 | LineEdit/colors/cursor_color = Color( 0.807843, 0.917647, 0.780392, 1 ) 118 | LineEdit/colors/font_color = Color( 0.733333, 0.823529, 0.819608, 1 ) 119 | LineEdit/colors/font_color_selected = Color( 0, 0, 0, 1 ) 120 | LineEdit/colors/font_color_uneditable = Color( 0.45098, 0.45098, 0.509804, 1 ) 121 | LineEdit/colors/selection_color = Color( 0.839216, 0.466667, 0.533333, 1 ) 122 | LineEdit/constants/minimum_spaces = 12 123 | LineEdit/fonts/font = null 124 | LineEdit/icons/clear = null 125 | LineEdit/styles/focus = SubResource( 7 ) 126 | LineEdit/styles/normal = SubResource( 8 ) 127 | LineEdit/styles/read_only = null 128 | MarginContainer/constants/margin_bottom = 20 129 | MarginContainer/constants/margin_left = 20 130 | MarginContainer/constants/margin_right = 20 131 | MarginContainer/constants/margin_top = 20 132 | PanelContainer/styles/panel = SubResource( 9 ) 133 | PopupMenu/colors/font_color = Color( 1, 1, 1, 1 ) 134 | PopupMenu/colors/font_color_accel = Color( 0.7, 0.7, 0.7, 0.8 ) 135 | PopupMenu/colors/font_color_disabled = Color( 0.4, 0.4, 0.4, 0.8 ) 136 | PopupMenu/colors/font_color_hover = Color( 0.88, 0.88, 0.88, 1 ) 137 | PopupMenu/colors/font_color_separator = Color( 0.88, 0.88, 0.88, 1 ) 138 | PopupMenu/constants/hseparation = 4 139 | PopupMenu/constants/vseparation = 4 140 | PopupMenu/fonts/font = null 141 | PopupMenu/icons/checked = null 142 | PopupMenu/icons/radio_checked = null 143 | PopupMenu/icons/radio_unchecked = null 144 | PopupMenu/icons/submenu = null 145 | PopupMenu/icons/unchecked = null 146 | PopupMenu/styles/hover = SubResource( 10 ) 147 | PopupMenu/styles/labeled_separator_left = SubResource( 10 ) 148 | PopupMenu/styles/labeled_separator_right = SubResource( 10 ) 149 | PopupMenu/styles/panel = SubResource( 10 ) 150 | PopupMenu/styles/panel_disabled = SubResource( 10 ) 151 | PopupMenu/styles/separator = SubResource( 10 ) 152 | Tree/colors/custom_button_font_highlight = Color( 0.807843, 0.917647, 0.780392, 1 ) 153 | Tree/colors/drop_position_color = Color( 1, 0.3, 0.2, 1 ) 154 | Tree/colors/font_color = Color( 0.733333, 0.823529, 0.819608, 1 ) 155 | Tree/colors/font_color_selected = Color( 0.807843, 0.917647, 0.780392, 1 ) 156 | Tree/colors/guide_color = Color( 0, 0, 0, 0.1 ) 157 | Tree/colors/relationship_line_color = Color( 0.270588, 0.270588, 0.270588, 0 ) 158 | Tree/colors/title_button_color = Color( 0.88, 0.88, 0.88, 1 ) 159 | Tree/constants/button_margin = 0 160 | Tree/constants/draw_guides = 0 161 | Tree/constants/draw_relationship_lines = 0 162 | Tree/constants/hseparation = 0 163 | Tree/constants/item_margin = 24 164 | Tree/constants/scroll_border = 4 165 | Tree/constants/scroll_speed = 12 166 | Tree/constants/vseparation = 6 167 | Tree/fonts/font = null 168 | Tree/fonts/title_button_font = null 169 | Tree/icons/arrow = ExtResource( 4 ) 170 | Tree/icons/arrow_collapsed = ExtResource( 3 ) 171 | Tree/icons/checked = null 172 | Tree/icons/select_arrow = null 173 | Tree/icons/unchecked = null 174 | Tree/icons/updown = null 175 | Tree/styles/bg = SubResource( 11 ) 176 | Tree/styles/bg_focus = null 177 | Tree/styles/button_pressed = SubResource( 12 ) 178 | Tree/styles/cursor = null 179 | Tree/styles/cursor_unfocused = null 180 | Tree/styles/custom_button = null 181 | Tree/styles/custom_button_hover = null 182 | Tree/styles/custom_button_pressed = null 183 | Tree/styles/selected = SubResource( 13 ) 184 | Tree/styles/selected_focus = SubResource( 14 ) 185 | Tree/styles/title_button_hover = null 186 | Tree/styles/title_button_normal = null 187 | Tree/styles/title_button_pressed = null 188 | VScrollBar/icons/decrement = null 189 | VScrollBar/icons/decrement_highlight = null 190 | VScrollBar/icons/increment = null 191 | VScrollBar/icons/increment_highlight = null 192 | VScrollBar/styles/grabber = SubResource( 15 ) 193 | VScrollBar/styles/grabber_highlight = SubResource( 16 ) 194 | VScrollBar/styles/grabber_pressed = SubResource( 17 ) 195 | VScrollBar/styles/scroll = SubResource( 18 ) 196 | VScrollBar/styles/scroll_focus = null 197 | VSeparator/constants/separation = 40 198 | VSeparator/styles/separator = SubResource( 19 ) 199 | WindowDialog/colors/title_color = Color( 0.807843, 0.917647, 0.780392, 1 ) 200 | WindowDialog/constants/close_h_ofs = 18 201 | WindowDialog/constants/close_v_ofs = 18 202 | WindowDialog/constants/scaleborder_size = 4 203 | WindowDialog/constants/title_height = 20 204 | WindowDialog/fonts/title_font = null 205 | WindowDialog/icons/close = ExtResource( 5 ) 206 | WindowDialog/icons/close_highlight = ExtResource( 5 ) 207 | WindowDialog/styles/panel = SubResource( 20 ) 208 | -------------------------------------------------------------------------------- /src/GDScriptAudioImport.gd: -------------------------------------------------------------------------------- 1 | #GDScriptAudioImport v0.1 2 | 3 | #MIT License 4 | # 5 | #Copyright (c) 2020 Gianclgar (Giannino Clemente) gianclgar@gmail.com 6 | # 7 | #Permission is hereby granted, free of charge, to any person obtaining a copy 8 | #of this software and associated documentation files (the "Software"), to deal 9 | #in the Software without restriction, including without limitation the rights 10 | #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | #copies of the Software, and to permit persons to whom the Software is 12 | #furnished to do so, subject to the following conditions: 13 | # 14 | #The above copyright notice and this permission notice shall be included in all 15 | #copies or substantial portions of the Software. 16 | # 17 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | #SOFTWARE. 24 | 25 | #I honestly don't care that much, Kopimi ftw, but it's my little baby and I want it to look nice :3 26 | 27 | extends Node 28 | 29 | func report_errors(err, filepath): 30 | # See: https://docs.godotengine.org/en/latest/classes/class_@globalscope.html#enum-globalscope-error 31 | var result_hash = { 32 | ERR_FILE_NOT_FOUND: "File: not found", 33 | ERR_FILE_BAD_DRIVE: "File: Bad drive error", 34 | ERR_FILE_BAD_PATH: "File: Bad path error.", 35 | ERR_FILE_NO_PERMISSION: "File: No permission error.", 36 | ERR_FILE_ALREADY_IN_USE: "File: Already in use error.", 37 | ERR_FILE_CANT_OPEN: "File: Can't open error.", 38 | ERR_FILE_CANT_WRITE: "File: Can't write error.", 39 | ERR_FILE_CANT_READ: "File: Can't read error.", 40 | ERR_FILE_UNRECOGNIZED: "File: Unrecognized error.", 41 | ERR_FILE_CORRUPT: "File: Corrupt error.", 42 | ERR_FILE_MISSING_DEPENDENCIES: "File: Missing dependencies error.", 43 | ERR_FILE_EOF: "File: End of file (EOF) error." 44 | } 45 | if err in result_hash: 46 | print("Error: ", result_hash[err], " ", filepath) 47 | else: 48 | print("Unknown error with file ", filepath, " error code: ", err) 49 | 50 | func loadfile(filepath, _loop = false): 51 | var file = File.new() 52 | var err = file.open(filepath, File.READ) 53 | if err != OK: 54 | report_errors(err, filepath) 55 | file.close() 56 | return AudioStreamSample.new() 57 | 58 | var bytes = file.get_buffer(file.get_len()) 59 | # if File is wav 60 | if filepath.ends_with(".wav"): 61 | var newstream = AudioStreamSample.new() 62 | 63 | #--------------------------- 64 | #parrrrseeeeee!!! :D 65 | print ("---") 66 | 67 | var bits_per_sample = 0 68 | 69 | for i in range(0, 100): 70 | var those4bytes = str(char(bytes[i])+char(bytes[i+1])+char(bytes[i+2])+char(bytes[i+3])) 71 | 72 | if those4bytes == "RIFF": 73 | print ("RIFF OK at bytes " + str(i) + "-" + str(i+3)) 74 | #RIP bytes 4-7 integer for now 75 | 76 | if those4bytes == "WAVE": 77 | print ("WAVE OK at bytes " + str(i) + "-" + str(i+3)) 78 | 79 | if those4bytes == "fmt ": 80 | print ("fmt OK at bytes " + str(i) + "-" + str(i+3)) 81 | 82 | #get format subchunk size, 4 bytes next to "fmt " are an int32 83 | var formatsubchunksize = bytes[i+4] + (bytes[i+5] << 8) + (bytes[i+6] << 16) + (bytes[i+7] << 24) 84 | print ("Format subchunk size: " + str(formatsubchunksize)) 85 | 86 | #using formatsubchunk index so it's easier to understand what's going on 87 | var fsc0 = i+8 #fsc0 is byte 8 after start of "fmt " 88 | 89 | #get format code [Bytes 0-1] 90 | var format_code = bytes[fsc0] + (bytes[fsc0+1] << 8) 91 | var format_name 92 | if format_code == 0: format_name = "8_BITS" 93 | elif format_code == 1: format_name = "16_BITS" 94 | elif format_code == 2: format_name = "IMA_ADPCM" 95 | else: 96 | format_name = "UNKNOWN (trying to interpret as 16_BITS)" 97 | format_code = 1 98 | print ("Format: " + str(format_code) + " " + format_name) 99 | #assign format to our AudioStreamSample 100 | newstream.format = format_code 101 | 102 | #get channel num [Bytes 2-3] 103 | var channel_num = bytes[fsc0+2] + (bytes[fsc0+3] << 8) 104 | print ("Number of channels: " + str(channel_num)) 105 | #set our AudioStreamSample to stereo if needed 106 | if channel_num == 2: newstream.stereo = true 107 | 108 | #get sample rate [Bytes 4-7] 109 | var sample_rate = bytes[fsc0+4] + (bytes[fsc0+5] << 8) + (bytes[fsc0+6] << 16) + (bytes[fsc0+7] << 24) 110 | print ("Sample rate: " + str(sample_rate)) 111 | #set our AudioStreamSample mixrate 112 | newstream.mix_rate = sample_rate 113 | 114 | #get byte_rate [Bytes 8-11] because we can 115 | var byte_rate = bytes[fsc0+8] + (bytes[fsc0+9] << 8) + (bytes[fsc0+10] << 16) + (bytes[fsc0+11] << 24) 116 | print ("Byte rate: " + str(byte_rate)) 117 | 118 | #same with bits*sample*channel [Bytes 12-13] 119 | var bits_sample_channel = bytes[fsc0+12] + (bytes[fsc0+13] << 8) 120 | print ("BitsPerSample * Channel / 8: " + str(bits_sample_channel)) 121 | 122 | #aaaand bits per sample/bitrate [Bytes 14-15] 123 | bits_per_sample = bytes[fsc0+14] + (bytes[fsc0+15] << 8) 124 | print ("Bits per sample: " + str(bits_per_sample)) 125 | 126 | if those4bytes == "data": 127 | assert(bits_per_sample != 0) 128 | 129 | var audio_data_size = bytes[i+4] + (bytes[i+5] << 8) + (bytes[i+6] << 16) + (bytes[i+7] << 24) 130 | print ("Audio data/stream size is " + str(audio_data_size) + " bytes") 131 | 132 | var data_entry_point = (i+8) 133 | print ("Audio data starts at byte " + str(data_entry_point)) 134 | 135 | var data = bytes.subarray(data_entry_point, data_entry_point+audio_data_size-1) 136 | 137 | if bits_per_sample in [24, 32]: 138 | newstream.data = convert_to_16bit(data, bits_per_sample) 139 | else: 140 | newstream.data = data 141 | # end of parsing 142 | #--------------------------- 143 | 144 | #get samples and set loop end 145 | var samplenum = newstream.data.size() / 4 146 | newstream.loop_end = samplenum 147 | newstream.loop_mode = 1 if _loop else 0 #change to 0 or delete this line if you don't want loop, also check out modes 2 and 3 in the docs 148 | return newstream #:D 149 | 150 | #if file is ogg 151 | elif filepath.ends_with(".ogg"): 152 | var newstream = AudioStreamOGGVorbis.new() 153 | newstream.loop = _loop #set to false or delete this line if you don't want to loop 154 | newstream.data = bytes 155 | return newstream 156 | 157 | #if file is mp3 158 | elif filepath.ends_with(".mp3"): 159 | var newstream = AudioStreamMP3.new() 160 | newstream.loop = _loop #set to false or delete this line if you don't want to loop 161 | newstream.data = bytes 162 | return newstream 163 | 164 | else: 165 | print ("ERROR: Wrong filetype or format") 166 | file.close() 167 | 168 | # Converts .wav data from 24 or 32 bits to 16 169 | # 170 | # These conversions are SLOW in GDScript 171 | # on my one test song, 32 -> 16 was around 3x slower than 24 -> 16 172 | # 173 | # I couldn't get threads to help very much 174 | # They made the 24bit case about 2x faster in my test file 175 | # And the 32bit case abour 50% slower 176 | # I don't wanna risk it always being slower on other files 177 | # And really, the solution would be to handle it in a low-level language 178 | func convert_to_16bit(data: PoolByteArray, from: int) -> PoolByteArray: 179 | print("converting to 16-bit from %d" % from) 180 | var time = OS.get_ticks_msec() 181 | # 24 bit .wav's are typically stored as integers 182 | # so we just grab the 2 most significant bytes and ignore the other 183 | if from == 24: 184 | var j = 0 185 | for i in range(0, data.size(), 3): 186 | data[j] = data[i+1] 187 | data[j+1] = data[i+2] 188 | j += 2 189 | data.resize(data.size() * 2 / 3) 190 | # 32 bit .wav's are typically stored as floating point numbers 191 | # so we need to grab all 4 bytes and interpret them as a float first 192 | if from == 32: 193 | var spb := StreamPeerBuffer.new() 194 | var single_float: float 195 | var value: int 196 | for i in range(0, data.size(), 4): 197 | spb.data_array = data.subarray(i, i+3) 198 | single_float = spb.get_float() 199 | value = single_float * 32768 200 | data[i/2] = value 201 | data[i/2+1] = value >> 8 202 | data.resize(data.size() / 2) 203 | print("Took %f seconds for slow conversion" % ((OS.get_ticks_msec() - time) / 1000.0)) 204 | return data 205 | 206 | 207 | # ---------- REFERENCE --------------- 208 | # note: typical values doesn't always match 209 | 210 | #Positions Typical Value Description 211 | # 212 | #1 - 4 "RIFF" Marks the file as a RIFF multimedia file. 213 | # Characters are each 1 byte long. 214 | # 215 | #5 - 8 (integer) The overall file size in bytes (32-bit integer) 216 | # minus 8 bytes. Typically, you'd fill this in after 217 | # file creation is complete. 218 | # 219 | #9 - 12 "WAVE" RIFF file format header. For our purposes, it 220 | # always equals "WAVE". 221 | # 222 | #13-16 "fmt " Format sub-chunk marker. Includes trailing null. 223 | # 224 | #17-20 16 Length of the rest of the format sub-chunk below. 225 | # 226 | #21-22 1 Audio format code, a 2 byte (16 bit) integer. 227 | # 1 = PCM (pulse code modulation). 228 | # 229 | #23-24 2 Number of channels as a 2 byte (16 bit) integer. 230 | # 1 = mono, 2 = stereo, etc. 231 | # 232 | #25-28 44100 Sample rate as a 4 byte (32 bit) integer. Common 233 | # values are 44100 (CD), 48000 (DAT). Sample rate = 234 | # number of samples per second, or Hertz. 235 | # 236 | #29-32 176400 (SampleRate * BitsPerSample * Channels) / 8 237 | # This is the Byte rate. 238 | # 239 | #33-34 4 (BitsPerSample * Channels) / 8 240 | # 1 = 8 bit mono, 2 = 8 bit stereo or 16 bit mono, 4 241 | # = 16 bit stereo. 242 | # 243 | #35-36 16 Bits per sample. 244 | # 245 | #37-40 "data" Data sub-chunk header. Marks the beginning of the 246 | # raw data section. 247 | # 248 | #41-44 (integer) The number of bytes of the data section below this 249 | # point. Also equal to (#ofSamples * #ofChannels * 250 | # BitsPerSample) / 8 251 | # 252 | #45+ The raw audio data. 253 | -------------------------------------------------------------------------------- /Main.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=32 format=2] 2 | 3 | [ext_resource path="res://src/Main.gd" type="Script" id=1] 4 | [ext_resource path="res://assets/logo.svg" type="Texture" id=2] 5 | [ext_resource path="res://assets/ic_folder.svg" type="Texture" id=3] 6 | [ext_resource path="res://assets/ui_theme.tres" type="Theme" id=4] 7 | [ext_resource path="res://assets/ic_loop.svg" type="Texture" id=5] 8 | [ext_resource path="res://assets/ic_stop.svg" type="Texture" id=6] 9 | [ext_resource path="res://src/AnalizeThread.gd" type="Script" id=7] 10 | [ext_resource path="res://src/DirectoryBrowser.gd" type="Script" id=8] 11 | [ext_resource path="res://src/Playlist.gd" type="Script" id=9] 12 | [ext_resource path="res://src/Playback.gd" type="Script" id=10] 13 | [ext_resource path="res://src/Export.gd" type="Script" id=11] 14 | [ext_resource path="res://assets/ic_clear.svg" type="Texture" id=12] 15 | [ext_resource path="res://src/MessageBox.gd" type="Script" id=13] 16 | [ext_resource path="res://assets/ic_info.svg" type="Texture" id=14] 17 | [ext_resource path="res://assets/ic_help.svg" type="Texture" id=15] 18 | [ext_resource path="res://src/HelpPanel.gd" type="Script" id=16] 19 | [ext_resource path="res://src/InfoBox.gd" type="Script" id=17] 20 | 21 | [sub_resource type="InputEventKey" id=1] 22 | control = true 23 | command = true 24 | scancode = 79 25 | 26 | [sub_resource type="ShortCut" id=2] 27 | shortcut = SubResource( 1 ) 28 | 29 | [sub_resource type="StyleBoxFlat" id=3] 30 | bg_color = Color( 0.733333, 0.823529, 0.819608, 1 ) 31 | 32 | [sub_resource type="Animation" id=4] 33 | resource_name = "hide" 34 | length = 0.3 35 | tracks/0/type = "value" 36 | tracks/0/path = NodePath(".:modulate") 37 | tracks/0/interp = 1 38 | tracks/0/loop_wrap = true 39 | tracks/0/imported = false 40 | tracks/0/enabled = true 41 | tracks/0/keys = { 42 | "times": PoolRealArray( 0.3 ), 43 | "transitions": PoolRealArray( 1 ), 44 | "update": 3, 45 | "values": [ Color( 1, 1, 1, 0 ) ] 46 | } 47 | tracks/1/type = "method" 48 | tracks/1/path = NodePath(".") 49 | tracks/1/interp = 1 50 | tracks/1/loop_wrap = true 51 | tracks/1/imported = false 52 | tracks/1/enabled = true 53 | tracks/1/keys = { 54 | "times": PoolRealArray( 0.3 ), 55 | "transitions": PoolRealArray( 1 ), 56 | "values": [ { 57 | "args": [ ], 58 | "method": "hide" 59 | } ] 60 | } 61 | 62 | [sub_resource type="StyleBoxEmpty" id=5] 63 | 64 | [sub_resource type="InputEventKey" id=6] 65 | scancode = 32 66 | 67 | [sub_resource type="ShortCut" id=7] 68 | shortcut = SubResource( 6 ) 69 | 70 | [sub_resource type="InputEventKey" id=8] 71 | scancode = 76 72 | 73 | [sub_resource type="ShortCut" id=9] 74 | shortcut = SubResource( 8 ) 75 | 76 | [sub_resource type="StyleBoxFlat" id=10] 77 | bg_color = Color( 0.807843, 0.917647, 0.780392, 1 ) 78 | 79 | [sub_resource type="Animation" id=11] 80 | length = 0.3 81 | tracks/0/type = "value" 82 | tracks/0/path = NodePath(".:modulate") 83 | tracks/0/interp = 1 84 | tracks/0/loop_wrap = true 85 | tracks/0/imported = false 86 | tracks/0/enabled = true 87 | tracks/0/keys = { 88 | "times": PoolRealArray( 0.3 ), 89 | "transitions": PoolRealArray( 1 ), 90 | "update": 3, 91 | "values": [ Color( 1, 1, 1, 0 ) ] 92 | } 93 | tracks/1/type = "method" 94 | tracks/1/path = NodePath(".") 95 | tracks/1/interp = 1 96 | tracks/1/loop_wrap = true 97 | tracks/1/imported = false 98 | tracks/1/enabled = true 99 | tracks/1/keys = { 100 | "times": PoolRealArray( 0.3 ), 101 | "transitions": PoolRealArray( 1 ), 102 | "values": [ { 103 | "args": [ ], 104 | "method": "hide" 105 | } ] 106 | } 107 | 108 | [sub_resource type="Animation" id=12] 109 | length = 0.3 110 | tracks/0/type = "value" 111 | tracks/0/path = NodePath(".:modulate") 112 | tracks/0/interp = 1 113 | tracks/0/loop_wrap = true 114 | tracks/0/imported = false 115 | tracks/0/enabled = true 116 | tracks/0/keys = { 117 | "times": PoolRealArray( 0.3 ), 118 | "transitions": PoolRealArray( 1 ), 119 | "update": 3, 120 | "values": [ Color( 1, 1, 1, 0 ) ] 121 | } 122 | tracks/1/type = "method" 123 | tracks/1/path = NodePath(".") 124 | tracks/1/interp = 1 125 | tracks/1/loop_wrap = true 126 | tracks/1/imported = false 127 | tracks/1/enabled = true 128 | tracks/1/keys = { 129 | "times": PoolRealArray( 0.3 ), 130 | "transitions": PoolRealArray( 1 ), 131 | "values": [ { 132 | "args": [ ], 133 | "method": "hide" 134 | } ] 135 | } 136 | 137 | [sub_resource type="StyleBoxFlat" id=13] 138 | bg_color = Color( 0.839216, 0.466667, 0.533333, 1 ) 139 | 140 | [sub_resource type="Animation" id=14] 141 | length = 0.3 142 | tracks/0/type = "value" 143 | tracks/0/path = NodePath(".:modulate") 144 | tracks/0/interp = 1 145 | tracks/0/loop_wrap = true 146 | tracks/0/imported = false 147 | tracks/0/enabled = true 148 | tracks/0/keys = { 149 | "times": PoolRealArray( 0.3 ), 150 | "transitions": PoolRealArray( 1 ), 151 | "update": 3, 152 | "values": [ Color( 1, 1, 1, 0 ) ] 153 | } 154 | tracks/1/type = "method" 155 | tracks/1/path = NodePath(".") 156 | tracks/1/interp = 1 157 | tracks/1/loop_wrap = true 158 | tracks/1/imported = false 159 | tracks/1/enabled = true 160 | tracks/1/keys = { 161 | "times": PoolRealArray( 0.3 ), 162 | "transitions": PoolRealArray( 1 ), 163 | "values": [ { 164 | "args": [ ], 165 | "method": "hide" 166 | } ] 167 | } 168 | 169 | [node name="Main" type="HSplitContainer"] 170 | anchor_right = 1.0 171 | anchor_bottom = 1.0 172 | theme = ExtResource( 4 ) 173 | script = ExtResource( 1 ) 174 | __meta__ = { 175 | "_edit_use_anchors_": false 176 | } 177 | 178 | [node name="PanelContainer" type="PanelContainer" parent="."] 179 | margin_right = 260.0 180 | margin_bottom = 600.0 181 | rect_min_size = Vector2( 260, 0 ) 182 | 183 | [node name="MarginContainer" type="MarginContainer" parent="PanelContainer"] 184 | margin_right = 260.0 185 | margin_bottom = 600.0 186 | __meta__ = { 187 | "_edit_use_anchors_": false 188 | } 189 | 190 | [node name="DirectoryBrowser" type="VBoxContainer" parent="PanelContainer/MarginContainer"] 191 | margin_left = 20.0 192 | margin_top = 20.0 193 | margin_right = 240.0 194 | margin_bottom = 580.0 195 | custom_constants/separation = 10 196 | script = ExtResource( 8 ) 197 | 198 | [node name="Load" type="Button" parent="PanelContainer/MarginContainer/DirectoryBrowser"] 199 | modulate = Color( 0.733333, 0.823529, 0.819608, 1 ) 200 | margin_right = 220.0 201 | margin_bottom = 25.0 202 | shortcut = SubResource( 2 ) 203 | text = "Root Folder" 204 | icon = ExtResource( 3 ) 205 | clip_text = true 206 | align = 0 207 | __meta__ = { 208 | "_edit_use_anchors_": false 209 | } 210 | 211 | [node name="BrowserHelp" type="PanelContainer" parent="PanelContainer/MarginContainer/DirectoryBrowser"] 212 | margin_top = 35.0 213 | margin_right = 220.0 214 | margin_bottom = 234.0 215 | custom_styles/panel = SubResource( 3 ) 216 | script = ExtResource( 16 ) 217 | 218 | [node name="AnimationPlayer" type="AnimationPlayer" parent="PanelContainer/MarginContainer/DirectoryBrowser/BrowserHelp"] 219 | anims/hide = SubResource( 4 ) 220 | 221 | [node name="MarginContainer" type="MarginContainer" parent="PanelContainer/MarginContainer/DirectoryBrowser/BrowserHelp"] 222 | margin_right = 220.0 223 | margin_bottom = 199.0 224 | 225 | [node name="HBoxContainer" type="HBoxContainer" parent="PanelContainer/MarginContainer/DirectoryBrowser/BrowserHelp/MarginContainer"] 226 | margin_left = 20.0 227 | margin_top = 20.0 228 | margin_right = 200.0 229 | margin_bottom = 179.0 230 | 231 | [node name="InfoBrowser" type="Label" parent="PanelContainer/MarginContainer/DirectoryBrowser/BrowserHelp/MarginContainer/HBoxContainer"] 232 | margin_right = 152.0 233 | margin_bottom = 159.0 234 | grow_vertical = 2 235 | size_flags_horizontal = 3 236 | size_flags_vertical = 0 237 | custom_colors/font_color = Color( 0.215686, 0.215686, 0.27451, 1 ) 238 | text = "ctrl + o 239 | 240 | Start by selecting which folder you want to rummage through." 241 | autowrap = true 242 | 243 | [node name="Close" type="Button" parent="PanelContainer/MarginContainer/DirectoryBrowser/BrowserHelp/MarginContainer/HBoxContainer"] 244 | modulate = Color( 0.215686, 0.215686, 0.27451, 1 ) 245 | margin_left = 156.0 246 | margin_right = 180.0 247 | margin_bottom = 25.0 248 | size_flags_horizontal = 0 249 | size_flags_vertical = 0 250 | icon = ExtResource( 12 ) 251 | flat = true 252 | 253 | [node name="Tree" type="Tree" parent="PanelContainer/MarginContainer/DirectoryBrowser"] 254 | margin_top = 244.0 255 | margin_right = 220.0 256 | margin_bottom = 560.0 257 | rect_min_size = Vector2( 0, 80 ) 258 | size_flags_vertical = 3 259 | hide_root = true 260 | 261 | [node name="FileDialog" type="FileDialog" parent="PanelContainer/MarginContainer/DirectoryBrowser"] 262 | margin_top = 386.0 263 | margin_right = 506.0 264 | margin_bottom = 578.0 265 | custom_colors/files_disabled = Color( 0.733333, 0.823529, 0.819608, 0.627451 ) 266 | custom_colors/file_icon_modulate = Color( 0.733333, 0.823529, 0.819608, 1 ) 267 | window_title = "Open a Directory" 268 | resizable = true 269 | mode = 2 270 | access = 2 271 | current_dir = "/home/richi/Projekte/SFX-Browser" 272 | current_path = "/home/richi/Projekte/SFX-Browser/" 273 | 274 | [node name="MarginContainer" type="MarginContainer" parent="."] 275 | margin_left = 272.0 276 | margin_right = 1024.0 277 | margin_bottom = 600.0 278 | custom_constants/margin_left = 6 279 | 280 | [node name="Workbench" type="VBoxContainer" parent="MarginContainer"] 281 | margin_left = 6.0 282 | margin_top = 20.0 283 | margin_right = 732.0 284 | margin_bottom = 580.0 285 | size_flags_horizontal = 15 286 | size_flags_vertical = 15 287 | custom_constants/separation = 10 288 | __meta__ = { 289 | "_edit_use_anchors_": false 290 | } 291 | 292 | [node name="Playback" type="HBoxContainer" parent="MarginContainer/Workbench"] 293 | margin_right = 726.0 294 | margin_bottom = 25.0 295 | mouse_filter = 2 296 | size_flags_horizontal = 15 297 | custom_constants/separation = 10 298 | script = ExtResource( 10 ) 299 | __meta__ = { 300 | "_edit_use_anchors_": false 301 | } 302 | 303 | [node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="MarginContainer/Workbench/Playback"] 304 | 305 | [node name="Logo" type="TextureRect" parent="MarginContainer/Workbench/Playback"] 306 | margin_right = 24.0 307 | margin_bottom = 25.0 308 | texture = ExtResource( 2 ) 309 | 310 | [node name="Title" type="Label" parent="MarginContainer/Workbench/Playback"] 311 | modulate = Color( 0.807843, 0.917647, 0.780392, 1 ) 312 | margin_left = 34.0 313 | margin_right = 138.0 314 | margin_bottom = 25.0 315 | size_flags_horizontal = 13 316 | size_flags_vertical = 15 317 | text = "SFX Browser" 318 | valign = 1 319 | __meta__ = { 320 | "_edit_use_anchors_": false 321 | } 322 | 323 | [node name="VSeparator2" type="VSeparator" parent="MarginContainer/Workbench/Playback"] 324 | margin_left = 148.0 325 | margin_right = 590.0 326 | margin_bottom = 25.0 327 | size_flags_horizontal = 3 328 | custom_styles/separator = SubResource( 5 ) 329 | 330 | [node name="Play" type="Button" parent="MarginContainer/Workbench/Playback"] 331 | modulate = Color( 0.45098, 0.45098, 0.509804, 1 ) 332 | margin_left = 600.0 333 | margin_right = 624.0 334 | margin_bottom = 25.0 335 | shortcut = SubResource( 7 ) 336 | icon = ExtResource( 6 ) 337 | __meta__ = { 338 | "_edit_use_anchors_": false 339 | } 340 | 341 | [node name="Loop" type="Button" parent="MarginContainer/Workbench/Playback"] 342 | modulate = Color( 0.45098, 0.45098, 0.509804, 1 ) 343 | margin_left = 634.0 344 | margin_right = 658.0 345 | margin_bottom = 25.0 346 | toggle_mode = true 347 | keep_pressed_outside = true 348 | shortcut = SubResource( 9 ) 349 | icon = ExtResource( 5 ) 350 | __meta__ = { 351 | "_edit_use_anchors_": false 352 | } 353 | 354 | [node name="Help" type="Button" parent="MarginContainer/Workbench/Playback"] 355 | modulate = Color( 0.45098, 0.45098, 0.509804, 1 ) 356 | margin_left = 668.0 357 | margin_right = 692.0 358 | margin_bottom = 25.0 359 | icon = ExtResource( 15 ) 360 | align = 0 361 | __meta__ = { 362 | "_edit_use_anchors_": false 363 | } 364 | 365 | [node name="Info" type="Button" parent="MarginContainer/Workbench/Playback"] 366 | modulate = Color( 0.45098, 0.45098, 0.509804, 1 ) 367 | margin_left = 702.0 368 | margin_right = 726.0 369 | margin_bottom = 25.0 370 | icon = ExtResource( 14 ) 371 | align = 0 372 | __meta__ = { 373 | "_edit_use_anchors_": false 374 | } 375 | 376 | [node name="InfoBox" type="PanelContainer" parent="MarginContainer/Workbench"] 377 | margin_top = 35.0 378 | margin_right = 726.0 379 | margin_bottom = 80.0 380 | custom_styles/panel = SubResource( 10 ) 381 | script = ExtResource( 17 ) 382 | 383 | [node name="AnimationPlayer" type="AnimationPlayer" parent="MarginContainer/Workbench/InfoBox"] 384 | anims/hide = SubResource( 11 ) 385 | 386 | [node name="MarginContainer" type="MarginContainer" parent="MarginContainer/Workbench/InfoBox"] 387 | margin_right = 726.0 388 | margin_bottom = 45.0 389 | custom_constants/margin_bottom = 0 390 | 391 | [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/Workbench/InfoBox/MarginContainer"] 392 | margin_left = 20.0 393 | margin_top = 20.0 394 | margin_right = 706.0 395 | margin_bottom = 45.0 396 | 397 | [node name="RichTextLabel" type="RichTextLabel" parent="MarginContainer/Workbench/InfoBox/MarginContainer/HBoxContainer"] 398 | margin_right = 658.0 399 | margin_bottom = 25.0 400 | size_flags_horizontal = 3 401 | custom_colors/default_color = Color( 0.215686, 0.215686, 0.27451, 1 ) 402 | bbcode_enabled = true 403 | bbcode_text = "SAMPLE BROWSER" 404 | text = "SAMPLE BROWSER" 405 | fit_content_height = true 406 | 407 | [node name="Close" type="Button" parent="MarginContainer/Workbench/InfoBox/MarginContainer/HBoxContainer"] 408 | modulate = Color( 0.215686, 0.215686, 0.27451, 1 ) 409 | margin_left = 662.0 410 | margin_right = 686.0 411 | margin_bottom = 25.0 412 | size_flags_horizontal = 0 413 | size_flags_vertical = 0 414 | icon = ExtResource( 12 ) 415 | flat = true 416 | 417 | [node name="PlaybackHelp" type="PanelContainer" parent="MarginContainer/Workbench"] 418 | margin_top = 90.0 419 | margin_right = 726.0 420 | margin_bottom = 289.0 421 | custom_styles/panel = SubResource( 3 ) 422 | script = ExtResource( 16 ) 423 | 424 | [node name="AnimationPlayer" type="AnimationPlayer" parent="MarginContainer/Workbench/PlaybackHelp"] 425 | anims/hide = SubResource( 12 ) 426 | 427 | [node name="MarginContainer" type="MarginContainer" parent="MarginContainer/Workbench/PlaybackHelp"] 428 | margin_right = 726.0 429 | margin_bottom = 199.0 430 | 431 | [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/Workbench/PlaybackHelp/MarginContainer"] 432 | margin_left = 20.0 433 | margin_top = 20.0 434 | margin_right = 706.0 435 | margin_bottom = 179.0 436 | custom_constants/separation = 20 437 | 438 | [node name="Info0" type="Label" parent="MarginContainer/Workbench/PlaybackHelp/MarginContainer/HBoxContainer"] 439 | margin_right = 145.0 440 | margin_bottom = 159.0 441 | grow_horizontal = 2 442 | grow_vertical = 2 443 | size_flags_horizontal = 3 444 | size_flags_vertical = 7 445 | custom_colors/font_color = Color( 0.215686, 0.215686, 0.27451, 1 ) 446 | text = "ctrl + o 447 | 448 | Start by selecting which folder you want to rummage through." 449 | autowrap = true 450 | 451 | [node name="Info1" type="Label" parent="MarginContainer/Workbench/PlaybackHelp/MarginContainer/HBoxContainer"] 452 | margin_left = 165.0 453 | margin_right = 311.0 454 | margin_bottom = 159.0 455 | grow_horizontal = 2 456 | grow_vertical = 2 457 | size_flags_horizontal = 3 458 | size_flags_vertical = 7 459 | custom_colors/font_color = Color( 0.215686, 0.215686, 0.27451, 1 ) 460 | text = "ctrl + o 461 | 462 | Start by selecting which folder you want to rummage through." 463 | autowrap = true 464 | 465 | [node name="Info2" type="Label" parent="MarginContainer/Workbench/PlaybackHelp/MarginContainer/HBoxContainer"] 466 | margin_left = 331.0 467 | margin_right = 476.0 468 | margin_bottom = 159.0 469 | grow_horizontal = 2 470 | grow_vertical = 2 471 | size_flags_horizontal = 3 472 | size_flags_vertical = 7 473 | custom_colors/font_color = Color( 0.215686, 0.215686, 0.27451, 1 ) 474 | text = "ctrl + o 475 | 476 | Start by selecting which folder you want to rummage through." 477 | autowrap = true 478 | 479 | [node name="Info3" type="Label" parent="MarginContainer/Workbench/PlaybackHelp/MarginContainer/HBoxContainer"] 480 | margin_left = 496.0 481 | margin_right = 642.0 482 | margin_bottom = 159.0 483 | grow_horizontal = 2 484 | grow_vertical = 2 485 | size_flags_horizontal = 3 486 | size_flags_vertical = 7 487 | custom_colors/font_color = Color( 0.215686, 0.215686, 0.27451, 1 ) 488 | text = "ctrl + o 489 | 490 | Start by selecting which folder you want to rummage through." 491 | autowrap = true 492 | 493 | [node name="Close" type="Button" parent="MarginContainer/Workbench/PlaybackHelp/MarginContainer/HBoxContainer"] 494 | modulate = Color( 0.215686, 0.215686, 0.27451, 1 ) 495 | margin_left = 662.0 496 | margin_right = 686.0 497 | margin_bottom = 25.0 498 | size_flags_horizontal = 0 499 | size_flags_vertical = 0 500 | icon = ExtResource( 12 ) 501 | flat = true 502 | 503 | [node name="HSeparator1" type="HSeparator" parent="MarginContainer/Workbench"] 504 | margin_top = 299.0 505 | margin_right = 726.0 506 | margin_bottom = 309.0 507 | size_flags_horizontal = 3 508 | 509 | [node name="Playlist" type="ScrollContainer" parent="MarginContainer/Workbench"] 510 | margin_top = 319.0 511 | margin_right = 726.0 512 | margin_bottom = 430.0 513 | size_flags_horizontal = 3 514 | size_flags_vertical = 3 515 | follow_focus = true 516 | scroll_horizontal_enabled = false 517 | script = ExtResource( 9 ) 518 | __meta__ = { 519 | "_edit_use_anchors_": false 520 | } 521 | 522 | [node name="AnalizeThread" type="Node" parent="MarginContainer/Workbench/Playlist"] 523 | script = ExtResource( 7 ) 524 | 525 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Workbench/Playlist"] 526 | margin_right = 726.0 527 | margin_bottom = 111.0 528 | size_flags_horizontal = 3 529 | size_flags_vertical = 15 530 | 531 | [node name="HSeparator2" type="HSeparator" parent="MarginContainer/Workbench"] 532 | margin_top = 440.0 533 | margin_right = 726.0 534 | margin_bottom = 450.0 535 | size_flags_horizontal = 3 536 | 537 | [node name="MessageBox" type="PanelContainer" parent="MarginContainer/Workbench"] 538 | margin_top = 460.0 539 | margin_right = 726.0 540 | margin_bottom = 525.0 541 | rect_min_size = Vector2( 0, 40 ) 542 | custom_styles/panel = SubResource( 13 ) 543 | script = ExtResource( 13 ) 544 | 545 | [node name="Timer" type="Timer" parent="MarginContainer/Workbench/MessageBox"] 546 | wait_time = 8.0 547 | one_shot = true 548 | 549 | [node name="AnimationPlayer" type="AnimationPlayer" parent="MarginContainer/Workbench/MessageBox"] 550 | anims/hide = SubResource( 14 ) 551 | 552 | [node name="MarginContainer" type="MarginContainer" parent="MarginContainer/Workbench/MessageBox"] 553 | margin_right = 726.0 554 | margin_bottom = 65.0 555 | 556 | [node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/Workbench/MessageBox/MarginContainer"] 557 | margin_left = 20.0 558 | margin_top = 20.0 559 | margin_right = 706.0 560 | margin_bottom = 45.0 561 | 562 | [node name="Label" type="Label" parent="MarginContainer/Workbench/MessageBox/MarginContainer/HBoxContainer"] 563 | margin_right = 658.0 564 | margin_bottom = 24.0 565 | size_flags_horizontal = 3 566 | custom_colors/font_color = Color( 0.215686, 0.215686, 0.27451, 1 ) 567 | text = "error text" 568 | 569 | [node name="Close" type="Button" parent="MarginContainer/Workbench/MessageBox/MarginContainer/HBoxContainer"] 570 | modulate = Color( 0.215686, 0.215686, 0.27451, 1 ) 571 | margin_left = 662.0 572 | margin_right = 686.0 573 | margin_bottom = 25.0 574 | size_flags_horizontal = 0 575 | size_flags_vertical = 0 576 | icon = ExtResource( 12 ) 577 | 578 | [node name="Export" type="HBoxContainer" parent="MarginContainer/Workbench"] 579 | margin_top = 535.0 580 | margin_right = 726.0 581 | margin_bottom = 560.0 582 | rect_min_size = Vector2( 0, 20 ) 583 | size_flags_horizontal = 3 584 | custom_constants/separation = 10 585 | script = ExtResource( 11 ) 586 | __meta__ = { 587 | "_edit_use_anchors_": false 588 | } 589 | 590 | [node name="Clear" type="Button" parent="MarginContainer/Workbench/Export"] 591 | modulate = Color( 0.733333, 0.823529, 0.819608, 1 ) 592 | margin_right = 138.0 593 | margin_bottom = 25.0 594 | text = "clear all" 595 | icon = ExtResource( 12 ) 596 | align = 0 597 | __meta__ = { 598 | "_edit_use_anchors_": false 599 | } 600 | 601 | [node name="VSeparator" type="VSeparator" parent="MarginContainer/Workbench/Export"] 602 | margin_left = 148.0 603 | margin_right = 188.0 604 | margin_bottom = 25.0 605 | 606 | [node name="ExportPath" type="Button" parent="MarginContainer/Workbench/Export"] 607 | modulate = Color( 0.733333, 0.823529, 0.819608, 1 ) 608 | margin_left = 198.0 609 | margin_right = 222.0 610 | margin_bottom = 25.0 611 | icon = ExtResource( 3 ) 612 | __meta__ = { 613 | "_edit_use_anchors_": false 614 | } 615 | 616 | [node name="FolderPath" type="Label" parent="MarginContainer/Workbench/Export"] 617 | margin_left = 232.0 618 | margin_right = 650.0 619 | margin_bottom = 25.0 620 | size_flags_horizontal = 15 621 | size_flags_vertical = 15 622 | text = "..." 623 | valign = 1 624 | __meta__ = { 625 | "_edit_use_anchors_": false 626 | } 627 | 628 | [node name="Export" type="Button" parent="MarginContainer/Workbench/Export"] 629 | margin_left = 660.0 630 | margin_right = 726.0 631 | margin_bottom = 25.0 632 | text = "export" 633 | __meta__ = { 634 | "_edit_use_anchors_": false 635 | } 636 | 637 | [node name="FileDialog" type="FileDialog" parent="MarginContainer/Workbench/Export"] 638 | margin_left = 269.0 639 | margin_right = 732.0 640 | margin_bottom = 143.0 641 | window_title = "Open a Directory" 642 | resizable = true 643 | mode = 2 644 | access = 2 645 | current_dir = "/home/richi/Projekte/SFX-Browser" 646 | current_path = "/home/richi/Projekte/SFX-Browser/" 647 | 648 | [connection signal="pressed" from="PanelContainer/MarginContainer/DirectoryBrowser/Load" to="PanelContainer/MarginContainer/DirectoryBrowser" method="_on_Load_pressed"] 649 | [connection signal="pressed" from="PanelContainer/MarginContainer/DirectoryBrowser/BrowserHelp/MarginContainer/HBoxContainer/Close" to="PanelContainer/MarginContainer/DirectoryBrowser/BrowserHelp" method="_on_Close_pressed"] 650 | [connection signal="item_selected" from="PanelContainer/MarginContainer/DirectoryBrowser/Tree" to="PanelContainer/MarginContainer/DirectoryBrowser" method="_on_Tree_item_selected"] 651 | [connection signal="dir_selected" from="PanelContainer/MarginContainer/DirectoryBrowser/FileDialog" to="PanelContainer/MarginContainer/DirectoryBrowser" method="_on_FileDialog_dir_selected"] 652 | [connection signal="finished" from="MarginContainer/Workbench/Playback/AudioStreamPlayer" to="MarginContainer/Workbench/Playback" method="_on_AudioStreamPlayer_finished"] 653 | [connection signal="pressed" from="MarginContainer/Workbench/Playback/Play" to="MarginContainer/Workbench/Playback" method="_on_Play_pressed"] 654 | [connection signal="toggled" from="MarginContainer/Workbench/Playback/Loop" to="MarginContainer/Workbench/Playback" method="_on_Loop_toggled"] 655 | [connection signal="pressed" from="MarginContainer/Workbench/Playback/Help" to="MarginContainer/Workbench/Playback" method="_on_Help_pressed"] 656 | [connection signal="pressed" from="MarginContainer/Workbench/Playback/Info" to="MarginContainer/Workbench/Playback" method="_on_Info_pressed"] 657 | [connection signal="meta_clicked" from="MarginContainer/Workbench/InfoBox/MarginContainer/HBoxContainer/RichTextLabel" to="MarginContainer/Workbench/InfoBox" method="_on_RichTextLabel_meta_clicked"] 658 | [connection signal="pressed" from="MarginContainer/Workbench/InfoBox/MarginContainer/HBoxContainer/Close" to="MarginContainer/Workbench/InfoBox" method="_on_Close_pressed"] 659 | [connection signal="pressed" from="MarginContainer/Workbench/PlaybackHelp/MarginContainer/HBoxContainer/Close" to="MarginContainer/Workbench/PlaybackHelp" method="_on_Close_pressed"] 660 | [connection signal="timeout" from="MarginContainer/Workbench/MessageBox/Timer" to="MarginContainer/Workbench/MessageBox" method="_on_Timer_timeout"] 661 | [connection signal="pressed" from="MarginContainer/Workbench/MessageBox/MarginContainer/HBoxContainer/Close" to="MarginContainer/Workbench/MessageBox" method="_on_Close_pressed"] 662 | [connection signal="pressed" from="MarginContainer/Workbench/Export/Clear" to="MarginContainer/Workbench/Export" method="_on_Clear_pressed"] 663 | [connection signal="pressed" from="MarginContainer/Workbench/Export/ExportPath" to="MarginContainer/Workbench/Export" method="_on_ExportPath_pressed"] 664 | [connection signal="pressed" from="MarginContainer/Workbench/Export/Export" to="MarginContainer/Workbench/Export" method="_on_Export_pressed"] 665 | [connection signal="dir_selected" from="MarginContainer/Workbench/Export/FileDialog" to="MarginContainer/Workbench/Export" method="_on_FileDialog_dir_selected"] 666 | --------------------------------------------------------------------------------