Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2023 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "brailleinputparser.h"
24 :
25 : #include <QString>
26 :
27 : #include "braillecode.h"
28 :
29 : namespace mu::engraving {
30 : static BiePattern pattern_accord = { "accord", { &Braille_FullMeasureAccord } };
31 :
32 : static BiePattern pattern_accidentals = { "accidental",
33 : { &Braille_NaturalAccidental, &Braille_SharpAccidental, &Braille_FlatAccidental } };
34 :
35 : static BiePattern pattern_octaves = { "octave",
36 : { &Braille_Octave0, &Braille_Octave1, &Braille_Octave2,
37 : &Braille_Octave3, &Braille_Octave4, &Braille_Octave5,
38 : &Braille_Octave6, &Braille_Octave7, &Braille_Octave8 } };
39 :
40 : static BiePattern pattern_notes ={ "note",
41 : { &Braille_aWhole, &Braille_aHalf, &Braille_aQuarter, &Braille_a8th,
42 : &Braille_bWhole, &Braille_bHalf, &Braille_bQuarter, &Braille_b8th,
43 : &Braille_cWhole, &Braille_cHalf, &Braille_cQuarter, &Braille_c8th,
44 : &Braille_dWhole, &Braille_dHalf, &Braille_dQuarter, &Braille_d8th,
45 : &Braille_eWhole, &Braille_eHalf, &Braille_eQuarter, &Braille_f8th,
46 : &Braille_fWhole, &Braille_fHalf, &Braille_fQuarter, &Braille_e8th,
47 : &Braille_gWhole, &Braille_gHalf, &Braille_gQuarter, &Braille_g8th } };
48 :
49 : static BiePattern pattern_c_notes ={ "c-note",
50 : { &Braille_cWhole, &Braille_cHalf, &Braille_cQuarter, &Braille_c8th } };
51 :
52 : static BiePattern pattern_dot = { "dot", { &Braille_Dot } };
53 : static BiePattern pattern_dot_2 = { "dot-2", { &Braille_Dot } };
54 : static BiePattern pattern_dot_3 = { "dot-3", { &Braille_Dot } };
55 : static BiePattern pattern_tie = { "tie", { &Braille_NoteTie } };
56 : static BiePattern pattern_note_slur = { "note-slur", { &Braille_NoteSlur } };
57 : static BiePattern pattern_slur_start = { "long-slur-start", { &Braille_LongSlurOpenBracket } };
58 : static BiePattern pattern_slur_stop = { "long-slur-stop", { &Braille_LongSlurCloseBracket } };
59 :
60 : static BiePattern pattern_rests ={ "rest",
61 : { &Braille_RestWhole, &Braille_RestHalf, &Braille_RestQuarter, &Braille_Rest8th } };
62 :
63 : static BiePattern pattern_intervals ={ "interval",
64 : { &Braille_Interval2, &Braille_Interval3, &Braille_Interval4, &Braille_Interval5,
65 : &Braille_Interval6, &Braille_Interval7, &Braille_Interval8 } };
66 :
67 : static BiePattern pattern_fingerings ={ "fingering",
68 : { &Braille_Finger0, &Braille_Finger1, &Braille_Finger2,
69 : &Braille_Finger3, &Braille_Finger4, &Braille_Finger5 } };
70 :
71 : static BiePattern pattern_tuplet_indicator ={ "tuplet-indicator", { &Braille_Tuplet3 } };
72 : static BiePattern pattern_tuplet3 ={ "tuplet3", { &Braille_Tuplet3 } };
73 : static BiePattern pattern_tuplet_prefix ={ "tuplet-prefix", { &Braille_TupletPrefix } };
74 : static BiePattern pattern_tuplet_suffix ={ "tuplet-suffix", { &Braille_Dot } };
75 :
76 : static BiePattern pattern_tuplet_numbers ={ "tuplet-number",
77 : { &Braille_Lower2, &Braille_Lower3, &Braille_Lower5, &Braille_Lower6,
78 : &Braille_Lower7, &Braille_Lower8, &Braille_Lower9 } };
79 :
80 0 : static int maxPatternLength(BiePattern* pattern)
81 : {
82 0 : int max = 0;
83 0 : for (auto code : pattern->codes) {
84 0 : if (code->num_cells > max) {
85 0 : max = code->num_cells;
86 : }
87 : }
88 0 : return max;
89 : }
90 :
91 0 : BieSequencePattern::BieSequencePattern(BieSequencePatternType t, std::string sequence)
92 : {
93 0 : _type = t;
94 0 : patterns.clear();
95 0 : max_cell_length = 0;
96 :
97 0 : size_t len = sequence.length();
98 0 : QString key;
99 0 : bool mandatory = false;
100 0 : char openning = ' ';
101 0 : for (size_t i = 0; i < len; ++i) {
102 0 : char c = sequence.at(i);
103 : //LOGD() << i << " c=" << c << " open=" << openning;
104 0 : switch (c) {
105 0 : case '(': {
106 0 : if (openning != ' ') {
107 0 : _valid = false;
108 0 : return;
109 : }
110 0 : mandatory = true;
111 0 : openning = '(';
112 0 : break;
113 : }
114 0 : case ')': {
115 0 : if (openning != '(') {
116 0 : _valid = false;
117 0 : return;
118 : }
119 0 : openning = ' ';
120 0 : break;
121 : }
122 0 : case '[': {
123 0 : if (openning != ' ') {
124 0 : _valid = false;
125 0 : return;
126 : }
127 0 : mandatory = false;
128 0 : openning = '[';
129 0 : break;
130 : }
131 0 : case ']': {
132 0 : if (openning != '[') {
133 0 : _valid = false;
134 0 : return;
135 : }
136 0 : openning = ' ';
137 0 : break;
138 : }
139 0 : case '{': {
140 : // ignore
141 0 : break;
142 : }
143 0 : case '}': {
144 : // ignore
145 0 : break;
146 : }
147 0 : default: {
148 0 : key.push_back(sequence.at(i));
149 0 : break;
150 : }
151 : }
152 :
153 0 : if (openning == ' ' && !key.isEmpty()) {
154 : //LOGD() << key << " " << mandatory;
155 0 : BiePattern* pattern = NULL;
156 0 : if (key == "accord") {
157 0 : pattern = &pattern_accord;
158 0 : } else if (key == "accord") {
159 0 : pattern = &pattern_accord;
160 0 : } else if (key == "accidental") {
161 0 : pattern = &pattern_accidentals;
162 0 : } else if (key == "octave") {
163 0 : pattern = &pattern_octaves;
164 0 : } else if (key == "note") {
165 0 : pattern = &pattern_notes;
166 0 : } else if (key == "dot") {
167 0 : pattern = &pattern_dot;
168 0 : } else if (key == "dot-2") {
169 0 : pattern = &pattern_dot_2;
170 0 : } else if (key == "dot-3") {
171 0 : pattern = &pattern_dot_3;
172 0 : } else if (key == "tie") {
173 0 : pattern = &pattern_tie;
174 0 : } else if (key == "note-slur") {
175 0 : pattern = &pattern_note_slur;
176 0 : } else if (key == "long-slur-start") {
177 0 : pattern = &pattern_slur_start;
178 0 : } else if (key == "long-slur-stop") {
179 0 : pattern = &pattern_slur_stop;
180 0 : } else if (key == "rest") {
181 0 : pattern = &pattern_rests;
182 0 : } else if (key == "interval") {
183 0 : pattern = &pattern_intervals;
184 0 : } else if (key == "fingering") {
185 0 : pattern = &pattern_fingerings;
186 0 : } else if (key == "tuplet-indicator") {
187 0 : pattern = &pattern_tuplet_indicator;
188 0 : } else if (key == "tuplet3") {
189 0 : pattern = &pattern_tuplet3;
190 0 : } else if (key == "tuplet-prefix") {
191 0 : pattern = &pattern_tuplet_prefix;
192 0 : } else if (key == "tuplet-number") {
193 0 : pattern = &pattern_tuplet_numbers;
194 0 : } else if (key == "tuplet-suffix") {
195 0 : pattern = &pattern_tuplet_suffix;
196 0 : } else if (key == "c-note") {
197 0 : pattern = &pattern_c_notes;
198 : }
199 0 : if (pattern != NULL) {
200 0 : patterns.push_back({ pattern->name, pattern->codes, mandatory });
201 0 : int n = maxPatternLength(pattern);
202 0 : if (max_cell_length < n) {
203 0 : max_cell_length = n;
204 : }
205 0 : if (mandatory) {
206 0 : _mandatories++;
207 : }
208 : }
209 0 : mandatory = false;
210 0 : key = QString();
211 : }
212 : }
213 0 : _valid = true;
214 0 : }
215 :
216 0 : BieSequencePattern::~BieSequencePattern()
217 : {
218 : // TODO
219 0 : }
220 :
221 0 : BieSequencePatternType BieSequencePattern::type() const
222 : {
223 0 : return _type;
224 : }
225 :
226 0 : bool BieSequencePattern::recognize(std::string braille)
227 : {
228 0 : _res.clear();
229 :
230 0 : size_t pos = 0;
231 0 : size_t cursor = 0;
232 :
233 0 : int mandatory_matches = 0;
234 0 : while (cursor < braille.length() && pos < patterns.size()) {
235 : //LOGD() << "cursor: " << cursor;
236 0 : bool match = false;
237 0 : for (auto code : patterns[pos].codes) {
238 0 : int len = code->num_cells;
239 0 : if (cursor + len <= braille.length()) {
240 0 : std::string bxt = braille.substr(cursor, len);
241 0 : if (bxt == code->braille) {
242 : //code->print();
243 0 : match = true;
244 0 : _res[patterns[pos].name] = code;
245 0 : if (patterns[pos].mandatory) {
246 0 : mandatory_matches++;
247 : }
248 0 : pos++;
249 0 : cursor += len;
250 0 : break;
251 : }
252 0 : }
253 : }
254 0 : if (!match) {
255 0 : if (patterns[pos].mandatory) {
256 0 : return false;
257 : } else {
258 0 : pos++;
259 : }
260 : }
261 : }
262 : //for(std::map<std::string, braille_code *>::iterator it = _res.begin(); it != _res.end(); ++it) {
263 : // LOGD() << "Key: " << it->first << " value: " << it->second->tag;
264 : //}
265 0 : return mandatory_matches == _mandatories && cursor >= braille.length();
266 : }
267 :
268 0 : const std::map<std::string, braille_code*>& BieSequencePattern::res() const
269 : {
270 0 : return _res;
271 : }
272 :
273 0 : braille_code* BieSequencePattern::res(std::string key)
274 : {
275 0 : return _res[key];
276 : }
277 :
278 0 : bool BieSequencePattern::valid() const
279 : {
280 0 : return _valid;
281 : }
282 :
283 0 : BieSequencePattern* BieRecognize(std::string braille, bool tuplet_indicator)
284 : {
285 : //static const std::string note_input_seq = "{[accord][long-slur-start][accidental][octave](note)[dot][dot-2][dot-3][fingering][note-slur][long-slur-stop][tie]}";
286 0 : static const std::string note_input_seq = "{[accord][long-slur-start][accidental][octave](note)}";
287 0 : static BieSequencePattern bie_note_input(BieSequencePatternType::Note, note_input_seq);
288 :
289 : //static const std::string rest_input_seq = "{[accord](rest)[dot][dot-2][dot-3][slur]}";
290 0 : static const std::string rest_input_seq = "{[accord](rest)}";
291 0 : static BieSequencePattern bie_rest_input(BieSequencePatternType::Rest, rest_input_seq);
292 :
293 0 : static const std::string interval_input_seq = "{[accidental][octave](interval)}";
294 0 : static BieSequencePattern bie_interval_input(BieSequencePatternType::Interval, interval_input_seq);
295 :
296 0 : static const std::string tuplet3_seq = "{(tuplet3)}";
297 0 : static BieSequencePattern bie_tuplet3(BieSequencePatternType::Tuplet3, tuplet3_seq);
298 :
299 0 : static const std::string tuplet_seq = "{(tuplet-prefix)(tuplet-number)(c-note)(tuplet-suffix)}";
300 0 : static BieSequencePattern bie_tuplet(BieSequencePatternType::Tuplet, tuplet_seq);
301 :
302 0 : static const std::string dot_seq = "{(dot)}";
303 0 : static BieSequencePattern bie_dot(BieSequencePatternType::Dot, dot_seq);
304 :
305 0 : static const std::string tie_seq = "{(tie)}";
306 0 : static BieSequencePattern bie_tie(BieSequencePatternType::Tie, tie_seq);
307 :
308 0 : static const std::string noteslur_seq = "{(note-slur)}";
309 0 : static BieSequencePattern bie_noteslur(BieSequencePatternType::NoteSlur, noteslur_seq);
310 :
311 0 : static const std::string longslur_seq = "{(long-slur-stop)}";
312 0 : static BieSequencePattern bie_longslur(BieSequencePatternType::LongSlurStop, longslur_seq);
313 :
314 0 : BieSequencePattern* res = NULL;
315 :
316 0 : if (!tuplet_indicator) { // check note input before tuplet
317 0 : if (bie_note_input.valid() && bie_note_input.recognize(braille)) {
318 0 : res = &bie_note_input;
319 0 : } else if (bie_rest_input.valid() && bie_rest_input.recognize(braille)) {
320 0 : res = &bie_rest_input;
321 0 : } else if (bie_interval_input.valid() && bie_interval_input.recognize(braille)) {
322 0 : res = &bie_interval_input;
323 0 : } else if (bie_tuplet3.valid() && bie_tuplet3.recognize(braille)) {
324 0 : res = &bie_tuplet3;
325 : //} else if(bie_tuplet.valid() && bie_tuplet.recognize(braille)) {
326 : // res = &bie_tuplet;
327 0 : } else if (bie_tie.valid() && bie_tie.recognize(braille)) {
328 0 : res = &bie_tie;
329 0 : } else if (bie_noteslur.valid() && bie_noteslur.recognize(braille)) {
330 0 : res = &bie_noteslur;
331 0 : } else if (bie_longslur.valid() && bie_longslur.recognize(braille)) {
332 0 : res = &bie_longslur;
333 0 : } else if (bie_dot.valid() && bie_dot.recognize(braille)) {
334 0 : res = &bie_dot;
335 : }
336 : } else { // check tuplet input
337 0 : if (bie_tuplet.valid() && bie_tuplet.recognize(braille)) {
338 0 : res = &bie_tuplet;
339 : }
340 : }
341 :
342 0 : return res;
343 : }
344 : }
|