bool load_tune(Tune& tune, const char* name) { FILE* f = fopen(name, "r"); if (!f) return false; Pattern* pat = nullptr; Macro* macro = nullptr; char s[1<<10]; int mode = 0; int line_nr = 0; while (fgets(s, sizeof(s), f)) { line_nr++; auto words = split(s); // comments if (words.empty()) continue; if (words[0][0] == '#') continue; // table line if (mode == 't') { if (!isspace(s[0])) mode = 0; else { tune.table.push_back({}); for (int i = 0; i < std::min<int>(CHANNEL_COUNT, words.size()); i++) { tune.table.back()[i] = strip_dots(words[i]); } continue; } } // pattern line if (mode == 'p') { if (!isspace(s[0]) || words.empty()) mode = 0; else { pat->push_back({}); auto& row = pat->back(); for (int i = 0; i < std::min<int>(MACROS_PER_ROW + 1, words.size()); i++) { auto& w = words[i]; if (i == 0) { if (w == "===") row.note = -1; else if (w == "...") row.note = 0; else { if (w.size() != 3 || w[0] < 'A' || w[0] > 'G' || (w[1] != '-' && w[1] != '#') || w[2] < '0' || w[2] > '9') { goto FAIL; } row.note = std::string("CCDDEFFGGAAB").find(w[0]) + 1; row.note += w[1] == '#'; row.note += (w[2] - '0') * 12; } } else row.macros[i - 1] = strip_dots(w); } continue; } } // macro line if (mode == 'm') { if (!isspace(s[0]) || words.empty()) mode = 0; else { peg::MacroLineState state; if (!pegtl::parse<peg::MacroLine,peg::MacroAction>(s, "", state)) goto FAIL; // printf(".\n", state.env.nodes.size()); macro->envs[state.name] = state.env; continue; } } if (words.size() == 1 && words[0] == "TABLE") { mode = 't'; tune.table.clear(); continue; } if (words.size() == 2 && words[0] == "PATTERN") { pat = &tune.patterns[words[1]]; pat->clear(); mode = 'p'; continue; } if (words.size() >= 2 && words[0] == "MACRO") { macro = &tune.macros[words[1]]; macro->envs.clear(); macro->parents.clear(); if (words.size() > 2) { if (words[2] != "<") goto FAIL; // parents for (int i = 3; i < (int) words.size(); i++) { macro->parents.push_back(words[i]); } } mode = 'm'; continue; } peg::MacroLineState state; if (pegtl::parse<peg::MacroLine,peg::MacroAction>(s, "", state)) { if (state.name == "frames") { if (state.env.nodes.size() != 1 || state.env.loop != -1) goto FAIL; tune.frames_per_tick = state.env.nodes[0].value; } else if (state.name == "ticks") tune.ticks_per_row = state.env; else tune.envs[state.name] = state.env; continue; } goto FAIL; } fclose(f); if (tune.table.empty()) tune.table.push_back({}); return true; FAIL: fclose(f); if (tune.table.empty()) tune.table.push_back({}); return false; }
void OscInputThread::clearPattern (int patternNum) { Pattern* pattern = library->getPattern (patternNum); pattern->clear(); }