-
Notifications
You must be signed in to change notification settings - Fork 7
/
tmb_info.gd
201 lines (172 loc) · 5.31 KB
/
tmb_info.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
class_name TMBInfo
extends Node
# { bar, length, start_pitch, delta_pitch, end_pitch } all floats
enum {
NOTE_BAR,
NOTE_LENGTH,
NOTE_PITCH_START,
NOTE_PITCH_DELTA,
NOTE_PITCH_END
}
enum LoadResult {
SUCCESS,
TMB_INVALID,
FILE_ACCESS_ERROR,
}
var notes := []
# { bar:float, lyric:string }
var lyrics := []
var improv_zones := []
var bgdata := []
var title := ""
var shortName := ""
var author := ""
var genre := ""
var description := ""
var trackRef := ""
var year : int = 1999
var tempo : float = 120
var endpoint : int = 4
var timesig : int = 2
var difficulty : int = 5
var savednotespacing : int = 120
# Assumes that the notes array is sorted. It's always sorted on drag end (including note addition),
# so this assumption should be OK, but testing against U/R may be needed.
func get_last_note_off() -> float:
if notes.is_empty(): return -1
return notes[-1][TMBInfo.NOTE_BAR] + notes[-1][TMBInfo.NOTE_LENGTH]
func has_note_touching_endpoint() -> bool:
if notes.is_empty(): return false
var last_note = notes[-1]
return (last_note[NOTE_BAR] + last_note[NOTE_LENGTH] == endpoint)
static func load_result_string(result:int) -> String:
match result:
LoadResult.SUCCESS: return "Loaded successfully"
LoadResult.TMB_INVALID: return "Invalid TMB"
LoadResult.FILE_ACCESS_ERROR: return "File access error (see console)"
_: return "Unknown error %d" % result
func find_all_notes_in_section(start:float,length:float) -> Array:
var result := []
var note_array = notes.duplicate(true)
var is_in_section := func(bar:float) -> bool:
return (bar >= start && bar < start + length)
for note in note_array:
var bar = note[NOTE_BAR]
var end = bar + note[NOTE_LENGTH]
if !is_in_section.call(bar) && !is_in_section.call(end): continue
note[NOTE_BAR] -= start
result.append(note)
return result
#func clear_section(start:float,length:float):
# var is_in_section := func(bar:float) -> bool:
# return (bar >= start && bar < start + length)
# print("Clear section %d - %d" % [start,length + start])
# var note_array = notes.duplicate(true)
# print("note_array: ",note_array)
#
# var any_notes_left : bool = true
# if note_array == [] : any_notes_left = false
# while any_notes_left:
# for note in note_array:
# var bar = note[NOTE_BAR]
# var end = bar + note[NOTE_LENGTH]
# print("%d notes left" % note_array.size())
# if is_in_section.call(bar) || is_in_section.call(end):
# print("Erase note @ %.3f" % bar)
# #TODO: index and save cleared note data for undo/redo
# note_array.erase(note)
# if note_array.is_empty(): any_notes_left = false
# break # start from the beginning of the array
#
# if note == note_array.back(): any_notes_left = false
# notes = note_array
func load_from_file(filename:String) -> int:
var f = FileAccess.open(filename,FileAccess.READ)
var err = FileAccess.get_open_error()
if err:
print(error_string(err))
return LoadResult.FILE_ACCESS_ERROR
var j = JSON.new()
err = j.parse(f.get_as_text())
if err:
print("%s\t| line %d\t| %s" % [
error_string(err), j.get_error_line() + 1, j.get_error_message()
])
return LoadResult.TMB_INVALID
var data = j.data
if typeof(data) != TYPE_DICTIONARY:
print("JSON got back object of type %s" % typeof(data))
return LoadResult.TMB_INVALID
notes = data.notes as Array[Dictionary]
lyrics = data.lyrics as Array[Dictionary]
title = data.name
shortName = data.shortName
author = data.author
genre = data.genre
description = data.description
trackRef = data.trackRef
year = data.year
tempo = data.tempo
endpoint = data.endpoint
timesig = data.timesig
difficulty = data.difficulty
savednotespacing = data.savednotespacing
if data.has('bgdata'):
bgdata = data.bgdata
else:
bgdata = []
if data.has('improv_zones') && data['improv_zones'] is Array:
improv_zones = data.improv_zones
else:
improv_zones = []
if data.has("note_color_start"):
Global.settings.use_custom_colors = true
Global.settings.start_color = Color(
data["note_color_start"][0],
data["note_color_start"][1],
data["note_color_start"][2]
)
Global.settings.end_color = Color(
data["note_color_end"][0],
data["note_color_end"][1],
data["note_color_end"][2]
)
return LoadResult.SUCCESS
func save_to_file(filename : String) -> int:
print("try save tmb to %s" % filename)
var f = FileAccess.open(filename,FileAccess.WRITE)
if f == null:
var err = FileAccess.get_open_error()
print(error_string(err))
return err
var dict := to_dict()
f.store_string(JSON.stringify(dict))
print("finished saving")
return OK
func to_dict() -> Dictionary:
var dict := {}
for value in Global.settings.values:
if !(value is TextField || value is NumField): continue
dict[value.json_key] = value.value
for note in notes: if (note[NOTE_BAR] + note[NOTE_LENGTH]) > endpoint: notes.erase(note)
for lyric in lyrics: if lyric.bar > endpoint: lyrics.erase(lyric)
dict["description"] = description
dict["notes"] = notes
dict["lyrics"] = lyrics
dict["improv_zones"] = improv_zones
dict["bgdata"] = bgdata
dict["UNK1"] = 0
if Global.settings.use_custom_colors:
var start_color = Global.settings.start_color
var end_color = Global.settings.end_color
dict["note_color_start"] = [
start_color[0],
start_color[1],
start_color[2],
]
dict["note_color_end"] = [
end_color[0],
end_color[1],
end_color[2],
]
return dict