| 169 | } |
| 170 | |
| 171 | List<Songbook::Note> Songbook::parseABC(String const& abc) { |
| 172 | List<Songbook::Note> result; |
| 173 | |
| 174 | StringMap<String> fields; |
| 175 | |
| 176 | auto meter = [&]() -> Vec2I { |
| 177 | auto m = fields.value("M", "C"); |
| 178 | if (m.equalsIgnoreCase("C")) |
| 179 | m = "4/4"; |
| 180 | if (m.equalsIgnoreCase("C|")) |
| 181 | m = "2/2"; |
| 182 | auto p = m.split("/", 1); |
| 183 | return Vec2I{lexicalCast<int>(p[0]), lexicalCast<int>(p[1])}; |
| 184 | }; |
| 185 | |
| 186 | auto noteLength = [&]() -> Vec2I { |
| 187 | auto m = fields.value("L", "C"); |
| 188 | if (m.equalsIgnoreCase("C")) |
| 189 | return {1, meter()[1]}; |
| 190 | auto p = m.split("/", 1); |
| 191 | return Vec2I{lexicalCast<int>(p[0]), lexicalCast<int>(p[1])}; |
| 192 | }; |
| 193 | |
| 194 | auto secondsPerBeat = [&]() -> double { |
| 195 | auto m = fields.value("Q", "120"); |
| 196 | auto p = m.split("=", 1); |
| 197 | double secondsPerBeat = 60.0 / lexicalCast<double>(p.last()); |
| 198 | if (p.size() > 1) { |
| 199 | auto pp = p[0].split("/", 1); |
| 200 | auto d = Vec2I{lexicalCast<int>(pp[0]), lexicalCast<int>(pp[1])}; |
| 201 | secondsPerBeat = d[1] * secondsPerBeat / d[0]; |
| 202 | } else |
| 203 | secondsPerBeat = noteLength()[1] * secondsPerBeat / noteLength()[0]; |
| 204 | return secondsPerBeat; |
| 205 | }; |
| 206 | |
| 207 | auto transpose = [&]() -> int { |
| 208 | auto t = fields.value("Transpose", "0"); |
| 209 | return lexicalCast<int>(t); |
| 210 | }; |
| 211 | |
| 212 | auto fetchKeySignatureMapping = [&]() -> List<int> { |
| 213 | auto cleanupKey = [](String const& key) -> String { |
| 214 | return key.toLower().replace(" ", "").replace("minor", "m").replace("min", "m").replace("major", "maj"); |
| 215 | }; |
| 216 | String key = cleanupKey(fields.value("K", "c")); |
| 217 | auto keys = Root::singleton().assets()->json("/songbook.config:keys"); |
| 218 | while (true) { |
| 219 | if (!keys.contains(key)) { |
| 220 | Logger::info("Failed to find key {}, falling back to C", key); |
| 221 | key = "c"; |
| 222 | } |
| 223 | auto signature = keys.get(key); |
| 224 | if (signature.isType(Json::Type::String)) { |
| 225 | key = cleanupKey(signature.toString()); |
| 226 | continue; |
| 227 | } |
| 228 | List<int> keySignatureMapping; |
nothing calls this directly
no test coverage detected