void FormatPattern(Pattern& pattern,std::vector<uint>& codeVec, 
		     std::vector<bool>& signVec){
    for(uint i=0; i<codeVec.size(); ++i){
      for(uint j=0; j<codeVec[i]; ++j)
	pattern.push_back(!signVec[i]);
    }
  }
Example #2
0
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;
}