Skip to content

Commit

Permalink
Catch parse errors in Song Script instead of crashing (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
IsotoxalDev authored Mar 3, 2023
1 parent f26bf65 commit fa79a42
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 39 deletions.
3 changes: 2 additions & 1 deletion Editor/Scenes/ControlPanel/ControlPanel.gd
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ func _on_StopButton_pressed():
buttons.Pause.disabled = true
buttons.Stop.disabled = true

func _on_finished():
func _on_finished(_n = ""):
yield(get_tree(), "idle_frame")
buttons.Play.disabled = false
buttons.Pause.disabled = true
buttons.Stop.disabled = true
Expand Down
3 changes: 0 additions & 3 deletions Editor/Scenes/ControlPanel/ControlPanel.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ margin_bottom = -5.0
custom_constants/separation = 10
alignment = 1
script = ExtResource( 7 )
__meta__ = {
"_edit_use_anchors_": false
}

[node name="PlayButton" type="TextureButton" parent="."]
margin_left = 565.0
Expand Down
18 changes: 15 additions & 3 deletions Editor/Scenes/Dialogues/DialogManager.gd
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
extends Control

onready var progress_dialog:WindowDialog = $ProgressDialog
onready var progress_dialog: PopupDialog = $ProgressDialog
onready var progress_label:Label = $ProgressDialog/VBoxContainer/Label
onready var progress_bar: ProgressBar = $ProgressDialog/VBoxContainer/ProgressBar

onready var error_dialog: WindowDialog = $ErrorDialog
onready var error_label: Label = $"%ErrorMessage"

onready var loading_dialog: PopupDialog = $Loading
onready var file_dialog: FileDialog = $FileDialog

onready var documents_dir = OS.get_system_dir(OS.SYSTEM_DIR_DOCUMENTS)

# Progress
func progress(title:String, text: String) -> ProgressBar:
progress_dialog.window_title = title
func progress(text: String) -> ProgressBar:
progress_label.text = text
progress_dialog.popup_centered()
return progress_bar
Expand All @@ -22,3 +26,11 @@ func file(title: String, mode: int, filters: Array) -> void:
file_dialog.filters = filters
file_dialog.current_dir = documents_dir
file_dialog.popup_centered()

# Error
func error(text: String):
error_label.text = text
error_dialog.popup_centered()

func start_loading(): loading_dialog.popup_centered()
func stop_loading(): loading_dialog.hide()
83 changes: 65 additions & 18 deletions Editor/Scenes/SongEditor/SongEditor.gd
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,21 @@ extends VBoxContainer

# Signals
signal playback_finished()
signal start_loading()
signal stop_loading()
signal done_error_handling(done)
signal done_error_check(error)
signal song_script_error(error)
signal track_pressed (name)

onready var SCRIPT_LOCATION = OS.get_user_data_dir() + "/song.gd"
onready var BIN = OS.get_executable_path()
var ERROR_REGEX = RegEx.new()
const SONG_PATH = "user://song.gd"

const BASE_SONG_SCRIPT = """extends SongScript
func song():
track("%s", [
# Place your notes here
Expand All @@ -14,13 +25,22 @@ func song():

var gui: bool = true
var track_name = preload("./TrackName.tscn")
var error_text = ""
var in_file = ""
var song_file: File

onready var thread = Thread.new()
onready var names = $TracksScroll/HBox/Names
onready var song_script_editor = $SongScriptEditor
onready var track_scroll = $TracksScroll
onready var sequencer = $Sequencer
onready var instrument_container = $InstrumentContainer

func _ready():
ERROR_REGEX.compile("SCRIPT ERROR: (.*?)\\n(?:.*?):([0-9]+)")
song_file = File.new()
connect("done_error_check", self, "_after_error_check")

# Takes a Button since it conveniently sends an icon and message
# TODO: Not use button as param
func add_track(instrument: Button):
Expand All @@ -34,27 +54,56 @@ func add_track(instrument: Button):
var inst := GoDAW.get_instrument(instrument.text)
$Sequencer.INSTRUMENTS[instrument.text] = inst

func check_error():
# Error check
var err = []
var _n = OS.execute(BIN, ["-s", SCRIPT_LOCATION, "--check-only", "--no-window"], true, err, true)
var error = ""
var regex_result = ERROR_REGEX.search(err[0])
if regex_result:
var regex_out = ERROR_REGEX.search(err[0]).get_strings()
error = "%s at SongScript:%s" % [regex_out[1], regex_out[2]]
emit_signal("done_error_check", error)

func _after_error_check(error):
emit_signal("stop_loading")
error_text = error
if error:
emit_signal("song_script_error", error_text)
return false

error_text = ""
var song: SongScript = load("user://song.gd").new()
if !song.has_method("song"):
emit_signal("song_script_error", "Script has no song method")
return false
song.sequence.tracks.clear()
song.song()
if song.sequence.tracks.size() != instrument_container.get_child_count():
sequencer.INSTRUMENTS.clear()
for instrument in instrument_container.get_children():
instrument.queue_free()
for track in song.sequence.tracks:
var inst = GoDAW.get_instrument(track.instrument)
sequencer.INSTRUMENTS[track.instrument] = inst
instrument_container.add_child(inst)
sequencer.sequence(song.sequence)
emit_signal("done_error_handling")

# Return true if everything goes alright
func sequence():
if !gui:
var file = File.new()
var dir = Directory.new()
file.open("res://song.gd", File.WRITE)
file.store_string(song_script_editor.text)
file.close()
var song: SongScript = load("res://song.gd").new()
song.entry()
if song.sequence.tracks.size() != instrument_container.get_child_count():
sequencer.INSTRUMENTS.clear()
for instrument in instrument_container.get_children():
instrument.queue_free()
for track in song.sequence.tracks:
var inst = GoDAW.get_instrument(track.instrument)
sequencer.INSTRUMENTS[track.instrument] = inst
instrument_container.add_child(inst)
sequencer.sequence(song.sequence)
emit_signal("start_loading")
if in_file != song_script_editor.text:
song_file.open(SONG_PATH, File.WRITE_READ)
song_file.store_string(song_script_editor.text)
song_file.close()
in_file = song_script_editor.text
thread.start(self, "check_error")

func _on_play():
sequence()
yield(self, "done_error_handling")
sequencer.play()

func _on_pause():
Expand All @@ -66,11 +115,9 @@ func _on_stop():
func _on_Sequencer_playback_finished():
emit_signal("playback_finished")


func _on_TrackEditor_sequence_song(sequence):
sequencer.sequence(sequence)


func project_changed(project: Project):
gui = true if project.project_type == Project.PROJECT_TYPE.GUI else false
song_script_editor.visible = !gui
Expand Down
1 change: 1 addition & 0 deletions Editor/Scenes/SongEditor/SongEditor.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ margin_bottom = 706.0

[node name="SongScriptEditor" parent="." instance=ExtResource( 1 )]
visible = false
margin_top = 14.0
margin_right = 1280.0
margin_bottom = 720.0

Expand Down
2 changes: 1 addition & 1 deletion Example.gd
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
extends SongScript

func entry():
func song():
var d = 0.275
track("TripleOsc", [
pattern([
Expand Down
15 changes: 10 additions & 5 deletions Main.gd
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func _on_TopMenu_export_pressed():
var recorder = AudioEffectRecord.new()
AudioServer.add_bus_effect(0, recorder, AudioServer.get_bus_effect_count(0))

var progress = dialog_manager.progress("Exporting", "Exporting...")
var progress = dialog_manager.progress("Exporting...")
progress.max_value = 100
sequencer.connect("on_note", progress, "set_value")

Expand Down Expand Up @@ -60,19 +60,24 @@ func _ready():
var font = get_theme().get_default_font().font_data
instrument_panel.title.get_font("font", "Label").font_data = font

#load instruments
var progress = dialog_manager.progress("Loading", "Loading...")
# Load instruments
var progress = dialog_manager.progress("Loading...")
var _n = GoDAW.connect("loading_progress_max_value_changed", progress, "set_max")
_n = GoDAW.connect("loading_progress_value_changed", progress, "set_value", [progress.value+1])
_n = GoDAW.connect("loading_instrument_changed", dialog_manager.progress_label, "set_text")
yield(GoDAW.load_instruments(), "completed")
dialog_manager.hide_progress()
instrument_panel.reload_instruments()

#Project setup
# Clear song history.
var dir = Directory.new()
dir.open("user://")
if dir.file_exists("song.gd"):
dir.remove("song.gd")

# Project setup
set_project(Project.new())

func set_project(new_project):
project = new_project
emit_signal("project_changed", project)

62 changes: 58 additions & 4 deletions Main.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ margin_right = 1264.0
margin_bottom = 704.0
script = ExtResource( 8 )

[node name="ProgressDialog" type="WindowDialog" parent="DialogManager"]
[node name="ProgressDialog" type="PopupDialog" parent="DialogManager"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
Expand All @@ -79,7 +79,6 @@ margin_top = -40.5
margin_right = 280.5
margin_bottom = 40.5
popup_exclusive = true
window_title = "Progress"

[node name="VBoxContainer" type="VBoxContainer" parent="DialogManager/ProgressDialog"]
anchor_right = 1.0
Expand All @@ -94,7 +93,7 @@ __meta__ = {
}

[node name="Label" type="Label" parent="DialogManager/ProgressDialog/VBoxContainer"]
margin_top = 8.0
margin_top = 10.0
margin_right = 545.0
margin_bottom = 27.0
text = "Progressing"
Expand All @@ -106,7 +105,37 @@ __meta__ = {
[node name="ProgressBar" type="ProgressBar" parent="DialogManager/ProgressDialog/VBoxContainer"]
margin_top = 31.0
margin_right = 545.0
margin_bottom = 56.0
margin_bottom = 54.0

[node name="Loading" type="PopupDialog" parent="DialogManager"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -280.5
margin_top = -40.5
margin_right = 280.5
margin_bottom = 40.5
popup_exclusive = true

[node name="VBoxContainer" type="VBoxContainer" parent="DialogManager/Loading"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 8.0
margin_top = 8.0
margin_right = -8.0
margin_bottom = -8.0
alignment = 1

[node name="Label" type="Label" parent="DialogManager/Loading/VBoxContainer"]
margin_top = 24.0
margin_right = 545.0
margin_bottom = 41.0
text = "Loading..."
align = 1
__meta__ = {
"_edit_use_anchors_": false
}

[node name="FileDialog" type="FileDialog" parent="DialogManager"]
rect_min_size = Vector2( 876, 480 )
Expand All @@ -118,6 +147,27 @@ filters = PoolStringArray( "*.wav ; Wav Files" )

[node name="NewSong" parent="DialogManager" instance=ExtResource( 9 )]

[node name="ErrorDialog" type="WindowDialog" parent="DialogManager"]
margin_right = 480.0
margin_bottom = 140.0
window_title = "Error"

[node name="ScrollContainer" type="ScrollContainer" parent="DialogManager/ErrorDialog"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3

[node name="ErrorMessage" type="Label" parent="DialogManager/ErrorDialog/ScrollContainer"]
unique_name_in_owner = true
margin_right = 480.0
margin_bottom = 140.0
size_flags_horizontal = 3
size_flags_vertical = 7
align = 1
valign = 1
autowrap = true

[connection signal="project_changed" from="." to="TopMenu" method="project_changed"]
[connection signal="project_changed" from="." to="Application/Main/SongEditor" method="project_changed"]
[connection signal="export_pressed" from="TopMenu" to="." method="_on_TopMenu_export_pressed"]
Expand All @@ -131,6 +181,10 @@ filters = PoolStringArray( "*.wav ; Wav Files" )
[connection signal="play" from="Application/Main/ControlPanel" to="Application/Main/SongEditor" method="_on_play"]
[connection signal="stop" from="Application/Main/ControlPanel" to="Application/Main/SongEditor" method="_on_stop"]
[connection signal="playback_finished" from="Application/Main/SongEditor" to="Application/Main/ControlPanel" method="_on_finished"]
[connection signal="song_script_error" from="Application/Main/SongEditor" to="Application/Main/ControlPanel" method="_on_finished"]
[connection signal="song_script_error" from="Application/Main/SongEditor" to="DialogManager" method="error"]
[connection signal="start_loading" from="Application/Main/SongEditor" to="DialogManager" method="start_loading"]
[connection signal="stop_loading" from="Application/Main/SongEditor" to="DialogManager" method="stop_loading"]
[connection signal="track_pressed" from="Application/Main/SongEditor" to="DialogManager/TrackEditor" method="_popup"]
[connection signal="confirmed" from="DialogManager/NewSong" to="DialogManager/NewSong" method="_confirmed"]
[connection signal="new_project" from="DialogManager/NewSong" to="." method="set_project"]
4 changes: 0 additions & 4 deletions addons/godaw_toolkit/API/SongScript.gd
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,3 @@ func note(note_start_delta: float, duration: float, data) -> Note:
# The function where notes go
func song():
pass

func entry():
sequence.tracks.clear()
song()

0 comments on commit fa79a42

Please sign in to comment.