#include #include #include #include #include #include #include struct Sample { std::string name; float freq, dur, amp, attack, harmonic_decay; int harmonics; }; struct Event { float beat; std::string sample_name; float volume, pan; }; struct Pattern { std::string name; std::vector events; }; struct Trigger { float time; std::string pattern_name; }; int main(int argc, char** argv) { if (argc < 3) { std::cerr << "Usage: " << argv[0] << " " << std::endl; return 1; } std::ifstream in(argv[1]); if (!in.is_open()) { std::cerr << "Could not open input file: " << argv[1] << std::endl; return 1; } float bpm = 120.0f; std::vector samples; std::map sample_map; std::vector patterns; std::map pattern_map; std::vector score; std::string line; std::string current_section = ""; while (std::getline(in, line)) { if (line.empty() || line[0] == '#') continue; std::stringstream ss(line); std::string cmd; ss >> cmd; if (cmd == "BPM") { ss >> bpm; } else if (cmd == "SAMPLE") { Sample s; std::string name; ss >> name; if (name.back() == ',') name.pop_back(); s.name = name; // Very simple parsing: freq, dur, amp, attack, harmonics, harmonic_decay char comma; ss >> s.freq >> comma >> s.dur >> comma >> s.amp >> comma >> s.attack >> comma >> s.harmonics >> comma >> s.harmonic_decay; sample_map[s.name] = samples.size(); samples.push_back(s); } else if (cmd == "PATTERN") { Pattern p; ss >> p.name; current_section = "PATTERN:" + p.name; patterns.push_back(p); pattern_map[p.name] = patterns.size() - 1; } else if (cmd == "SCORE") { current_section = "SCORE"; } else { if (current_section.rfind("PATTERN:", 0) == 0) { // Parse event: beat, sample, vol, pan Event e; float beat; std::stringstream ss2(line); ss2 >> beat; char comma; ss2 >> comma; std::string sname; ss2 >> sname; if (sname.back() == ',') sname.pop_back(); e.beat = beat; e.sample_name = sname; ss2 >> e.volume >> comma >> e.pan; patterns.back().events.push_back(e); } else if (current_section == "SCORE") { Trigger t; float time; std::stringstream ss2(line); ss2 >> time; char comma; ss2 >> comma; std::string pname; ss2 >> pname; t.time = time; t.pattern_name = pname; score.push_back(t); } } } std::ofstream out(argv[2]); out << "// Generated by tracker_compiler. Do not edit.\n\n"; out << "#include \"audio/tracker.h\"\n\n"; out << "const NoteParams g_tracker_samples[] = {\n"; for (const auto& s : samples) { out << " { " << s.freq << "f, " << s.dur << "f, " << s.amp << "f, " << s.attack << "f, 0.0f, 0.0f, 0.0f, " << s.harmonics << ", " << s.harmonic_decay << "f, 0.0f, 0.0f }, // " << s.name << "\n"; } out << "}; "; out << "const uint32_t g_tracker_samples_count = " << samples.size() << ";\n\n"; for (const auto& p : patterns) { out << "static const TrackerEvent PATTERN_EVENTS_" << p.name << "[] = {\n"; for (const auto& e : p.events) { out << " { " << e.beat << "f, " << sample_map[e.sample_name] << ", " << e.volume << "f, " << e.pan << "f },\n"; } out << "}; "; } out << "\n"; out << "const TrackerPattern g_tracker_patterns[] = {\n"; for (const auto& p : patterns) { out << " { PATTERN_EVENTS_" << p.name << ", " << p.events.size() << ", 4.0f }, // " << p.name << "\n"; } out << "}; "; out << "const uint32_t g_tracker_patterns_count = " << patterns.size() << ";\n\n"; out << "static const TrackerPatternTrigger SCORE_TRIGGERS[] = {\n"; for (const auto& t : score) { out << " { " << t.time << "f, " << pattern_map[t.pattern_name] << " },\n"; } out << "}; \n"; out << "const TrackerScore g_tracker_score = {\n"; out << " SCORE_TRIGGERS, " << score.size() << ", " << bpm << "f\n"; out << "}; "; return 0; }