Skip to content

Commit

Permalink
Further fix circular macro checks
Browse files Browse the repository at this point in the history
This was completely not operational in the
original synth, but my initial attempt to fix it was
faulty as well. This broke a handful of MML songs
which we showcase in the example app.

Also includes some adjustments to the example
app, namely the volume slider (some MML songs
are way too loud otherwise).
  • Loading branch information
YuriSizov committed Sep 26, 2024
1 parent de71dd6 commit 8290a46
Show file tree
Hide file tree
Showing 10 changed files with 113 additions and 24 deletions.
3 changes: 3 additions & 0 deletions example/Main.gd
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extends Control
@onready var _piano_view: Control = %PianoView
@onready var _tunes_view: Control = %TunesView

@onready var _volume_slider: HSlider = %VolumeSlider
@onready var _kenney_label := %KenneyLabel

var _current_view: Controller.AppView = Controller.AppView.WELCOME_VIEW
Expand All @@ -23,9 +24,11 @@ var _current_view: Controller.AppView = Controller.AppView.WELCOME_VIEW
func _ready() -> void:
get_window().min_size = Vector2(640, 360)
_update_active_view(Controller.AppView.WELCOME_VIEW, true)
Controller.music_player.change_volume(int(_volume_slider.value))

_piano_view_button.pressed.connect(Controller.change_app_view.bind(Controller.AppView.PIANO_VIEW))
_tunes_view_button.pressed.connect(Controller.change_app_view.bind(Controller.AppView.TUNES_VIEW))
_volume_slider.value_changed.connect(Controller.music_player.change_volume)
_kenney_label.meta_clicked.connect(_handle_meta_clicked)

Controller.app_view_changed.connect(_update_active_view.bind(false))
Expand Down
34 changes: 30 additions & 4 deletions example/Main.tscn
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[gd_scene load_steps=9 format=3 uid="uid://btlcavlirkxet"]
[gd_scene load_steps=10 format=3 uid="uid://btlcavlirkxet"]

[ext_resource type="Script" path="res://Main.gd" id="1_8sk4m"]
[ext_resource type="PackedScene" uid="uid://dp02gpc8hg7fw" path="res://gui/components/FlatButton.tscn" id="2_7ss6h"]
Expand All @@ -8,6 +8,7 @@
[ext_resource type="Texture2D" uid="uid://5pxu35ux4hkn" path="res://icons/piano.png" id="3_cw50e"]
[ext_resource type="PackedScene" uid="uid://cwl0nh1ofpudo" path="res://gui/TunesView.tscn" id="3_k0wkn"]
[ext_resource type="Texture2D" uid="uid://ceui0jym6bois" path="res://icons/note.png" id="4_s2pjj"]
[ext_resource type="Texture2D" uid="uid://cunfeny5nkxdn" path="res://icons/volume.png" id="9_te82j"]

[node name="Main" type="Control"]
layout_mode = 3
Expand All @@ -28,7 +29,7 @@ grow_vertical = 2
theme_override_constants/margin_left = 12
theme_override_constants/margin_top = 110
theme_override_constants/margin_right = 12
theme_override_constants/margin_bottom = 36
theme_override_constants/margin_bottom = 48

[node name="WelcomeView" parent="Views" instance=ExtResource("2_d1bku")]
unique_name_in_owner = true
Expand Down Expand Up @@ -62,12 +63,12 @@ text = "GDSiON"

[node name="ViewSelectorFiller" type="Control" parent="TopBar"]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_horizontal = 3

[node name="ViewSelector" type="HBoxContainer" parent="TopBar"]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_horizontal = 3
alignment = 1
Expand All @@ -94,6 +95,31 @@ texture = ExtResource("3_7khnb")
expand_mode = 1
stretch_mode = 5

[node name="Volume" type="HBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_left = 10.0
offset_top = -40.0
offset_right = 246.0
offset_bottom = -8.0
grow_vertical = 0

[node name="VolumeIcon" type="TextureRect" parent="Volume"]
custom_minimum_size = Vector2(32, 32)
layout_mode = 2
texture = ExtResource("9_te82j")
expand_mode = 1
stretch_mode = 5

[node name="VolumeSlider" type="HSlider" parent="Volume"]
unique_name_in_owner = true
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
size_flags_vertical = 1
value = 75.0

[node name="KenneyLabel" type="RichTextLabel" parent="."]
unique_name_in_owner = true
layout_mode = 1
Expand All @@ -104,7 +130,7 @@ anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -249.0
offset_top = -27.0
offset_right = -2.0
offset_right = -7.0
offset_bottom = -7.0
grow_horizontal = 0
grow_vertical = 0
Expand Down
6 changes: 6 additions & 0 deletions example/globals/MusicPlayer.gd
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ func change_filter_power(value: int) -> void:
filter_changed.emit()


func change_volume(value: int) -> void:
var volume := clampi(value, 0, 100)

_driver.volume = (volume / 100.0)


# Output and streaming control.

func stop() -> void:
Expand Down
3 changes: 3 additions & 0 deletions example/gui/TunesView.gd
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func _ready() -> void:
func _set_view_active() -> void:
if not visible:
_tune_status.text = ""
_tune_status.tooltip_text = ""
return


Expand All @@ -48,11 +49,13 @@ func _play_selected() -> void:
_tune_status.text = "Now Playing: %s" % [ selected_tune.title ]
else:
_tune_status.text = "Now Playing: %s by %s" % [ selected_tune.title, selected_tune.author ]
_tune_status.tooltip_text = _tune_status.text


func _stop_playback() -> void:
Controller.music_player.stop()
_tune_status.text = ""
_tune_status.tooltip_text = ""


# Tune management.
Expand Down
4 changes: 3 additions & 1 deletion example/gui/TunesView.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ theme_override_constants/separation = 16

[node name="Controls" type="HBoxContainer" parent="Layout/Playback"]
layout_mode = 2
size_flags_horizontal = 8
theme_override_constants/separation = 12
alignment = 2

[node name="PlayButton" parent="Layout/Playback/Controls" instance=ExtResource("2_c6y1p")]
unique_name_in_owner = true
Expand All @@ -59,7 +59,9 @@ size_flags_vertical = 3
[node name="TuneStatus" type="Label" parent="Layout/Playback"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 1
theme_override_font_sizes/font_size = 24
text_overrun_behavior = 1

[node name="HTTPRequest" type="HTTPRequest" parent="."]
unique_name_in_owner = true
Binary file added example/icons/volume.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions example/icons/volume.png.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://cunfeny5nkxdn"
path="res://.godot/imported/volume.png-4aaf602240d33d2298951d35d959a50c.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://icons/volume.png"
dest_files=["res://.godot/imported/volume.png-4aaf602240d33d2298951d35d959a50c.ctex"]

[params]

compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
19 changes: 18 additions & 1 deletion example/project_theme.tres
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[gd_resource type="Theme" load_steps=7 format=3 uid="uid://bm402itx0nq0t"]
[gd_resource type="Theme" load_steps=8 format=3 uid="uid://bm402itx0nq0t"]

[ext_resource type="FontFile" uid="uid://c4b0xfmxt4on2" path="res://fonts/NotoSans-SemiBold.ttf" id="1_2oopj"]
[ext_resource type="FontFile" uid="uid://y70lqerdtol1" path="res://fonts/Kenney Future Narrow.ttf" id="1_8d45h"]
Expand Down Expand Up @@ -27,6 +27,22 @@ corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4

[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_wqqdn"]
content_margin_left = 12.0
content_margin_top = 8.0
content_margin_right = 12.0
content_margin_bottom = 8.0
bg_color = Color(0.123694, 0.138055, 0.166794, 1)
border_width_left = 1
border_width_top = 1
border_width_right = 1
border_width_bottom = 1
border_color = Color(0.0343809, 0.0400633, 0.0557284, 1)
corner_radius_top_left = 2
corner_radius_top_right = 2
corner_radius_bottom_right = 2
corner_radius_bottom_left = 2

[resource]
default_font = ExtResource("1_8d45h")
default_font_size = 30
Expand All @@ -50,5 +66,6 @@ ItemList/styles/panel = SubResource("StyleBoxFlat_h73hr")
ItemList/styles/selected = SubResource("StyleBoxFlat_6uu3r")
TooltipLabel/font_sizes/font_size = 20
TooltipLabel/fonts/font = ExtResource("1_2oopj")
TooltipPanel/styles/panel = SubResource("StyleBoxFlat_wqqdn")
WelcomeLabel/base_type = &"Label"
WelcomeLabel/fonts/font = ExtResource("1_2oopj")
32 changes: 15 additions & 17 deletions src/sequencer/simml_sequencer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,51 +472,49 @@ void SiMMLSequencer::process() {

// Parser.

String SiMMLSequencer::_expand_macro(String p_macro, bool p_nested) {
String SiMMLSequencer::_expand_macro(String p_macro, uint32_t p_macro_flags) {
// Note that the original code has a broken circular call check. It never updates the flag
// storage, and the check is written incorrectly too. We attempt to fix it here based on the
// intention of the original code rather than the actual implementation.

static uint32_t flag_macro_expanded = 0;

if (p_macro.is_empty()) {
return "";
}

if (!p_nested) {
// This is a top-level call, so we reset the flag storage.
// We expect only one chain of _expand_macro() calls to be executed at the same time.
flag_macro_expanded = 0;
}

String expanded_macro = p_macro;

Ref<RegEx> re_macro = RegEx::create_from_string("([A-Z])(\\(([\\-\\d]+)\\))?");
TypedArray<RegExMatch> matches = re_macro->search_all(expanded_macro);
// Iterate backwards so we can do in-place replacements without disturbing indices.
for (int i = matches.size() - 1; i >= 0; i--) {
Ref<RegExMatch> res = matches[i];

int index = res->get_string(1).unicode_at(0) - 'A';

// Check for circular calls.

// The set of flags is unique to each chain of nested calls, which is how we detect circular
// calls without getting false positives on sibling macros (e.g. "AAA").
uint32_t expanded_macro_flags = p_macro_flags;

int flag = 1 << index;
ERR_FAIL_COND_V_MSG(flag_macro_expanded & flag, p_macro, vformat("SiMMLSequencer: Failed to expand a macro due to a circular reference, '%s'.", res->get_string()));
flag_macro_expanded |= flag;
ERR_FAIL_COND_V_MSG(expanded_macro_flags & flag, p_macro, vformat("SiMMLSequencer: Failed to expand a macro due to a circular reference, '%s'.", res->get_string()));
expanded_macro_flags |= flag;

// Find the replacement string.

String replacement;
if (!_macro_strings[index].is_empty()) {
const String macro_string = _macro_strings[index];
replacement = (_macro_expand_dynamic ? _expand_macro(macro_string, expanded_macro_flags) : macro_string);

// Apply a note shift to the expanded macro.
if (!res->get_string(2).is_empty()) {
int t = 0;
int note_shift = 0;
if (!res->get_string(3).is_empty()) {
t = res->get_string(3).to_int();
note_shift = res->get_string(3).to_int();
}

replacement = "!@ns" + itos(t) + (_macro_expand_dynamic ? _expand_macro(macro_string, true) : macro_string) + "!@ns" + itos(-t);
} else {
replacement = (_macro_expand_dynamic ? _expand_macro(macro_string, true) : macro_string);
replacement = "!@ns" + itos(note_shift) + replacement + "!@ns" + itos(-note_shift);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/sequencer/simml_sequencer.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class SiMMLSequencer : public MMLSequencer {
Vector<String> _macro_strings;
bool _macro_expand_dynamic = false;

String _expand_macro(String p_macro, bool p_nested = false);
String _expand_macro(String p_macro, uint32_t p_macro_flags = 0);

int _internal_table_index = 0;

Expand Down

0 comments on commit 8290a46

Please sign in to comment.