summaryrefslogtreecommitdiff
path: root/tools/seq_compiler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/seq_compiler.cc')
-rw-r--r--tools/seq_compiler.cc132
1 files changed, 117 insertions, 15 deletions
diff --git a/tools/seq_compiler.cc b/tools/seq_compiler.cc
index 8956c32..a4fd00c 100644
--- a/tools/seq_compiler.cc
+++ b/tools/seq_compiler.cc
@@ -20,17 +20,48 @@ struct EffectEntry {
struct SequenceEntry {
std::string start_time;
std::string priority;
+ std::string end_time; // Optional: -1.0f means "no explicit end"
std::vector<EffectEntry> effects;
};
std::string trim(const std::string& str) {
- size_t first = str.find_first_not_of(" ");
+ size_t first = str.find_first_not_of(" \t");
if (std::string::npos == first)
- return str;
- size_t last = str.find_last_not_of(" ");
+ return ""; // String is all whitespace, return empty string
+ size_t last = str.find_last_not_of(" \t");
return str.substr(first, (last - first + 1));
}
+// Convert beat notation to time in seconds
+// Supports: "64b" or "64" (beats), "32.0s" or "32.0" with decimal point (seconds)
+std::string convert_to_time(const std::string& value, float bpm) {
+ std::string val = value;
+ bool is_beat = false;
+
+ // Check for explicit 'b' suffix (beat)
+ if (!val.empty() && val.back() == 'b') {
+ is_beat = true;
+ val.pop_back();
+ }
+ // Check for explicit 's' suffix (seconds)
+ else if (!val.empty() && val.back() == 's') {
+ val.pop_back();
+ return val; // Already in seconds
+ }
+ // If no suffix and no decimal point, assume beats
+ else if (val.find('.') == std::string::npos) {
+ is_beat = true;
+ }
+
+ if (is_beat) {
+ float beat = std::stof(val);
+ float time = beat * 60.0f / bpm;
+ return std::to_string(time);
+ }
+
+ return val; // Return as-is (seconds)
+}
+
int main(int argc, char* argv[]) {
if (argc != 3) {
std::cerr << "Usage: " << argv[0] << " <input.seq> <output.cc>\n";
@@ -47,27 +78,72 @@ int main(int argc, char* argv[]) {
std::vector<SequenceEntry> sequences;
SequenceEntry* current_seq = nullptr;
+ float bpm = 120.0f; // Default BPM
+ std::string demo_end_time = ""; // Demo end time (optional)
std::string line;
int line_num = 0;
while (std::getline(in_file, line)) {
++line_num;
std::string trimmed = trim(line);
- if (trimmed.empty() || trimmed[0] == '#')
+ if (trimmed.empty())
+ continue;
+
+ // Parse BPM from comment
+ if (trimmed[0] == '#') {
+ std::stringstream ss(trimmed);
+ std::string hash, keyword;
+ ss >> hash >> keyword;
+ if (keyword == "BPM") {
+ ss >> bpm;
+ std::cout << "Using BPM: " << bpm << "\n";
+ }
continue;
+ }
std::stringstream ss(trimmed);
std::string command;
ss >> command;
- if (command == "SEQUENCE") {
+ if (command == "END_DEMO") {
+ std::string end_time;
+ if (!(ss >> end_time)) {
+ std::cerr << "Error line " << line_num
+ << ": END_DEMO requires <time>\n";
+ return 1;
+ }
+ // Convert beat notation to time
+ demo_end_time = convert_to_time(end_time, bpm);
+ std::cout << "Demo end time: " << demo_end_time << "s\n";
+ } else if (command == "SEQUENCE") {
std::string start, priority;
if (!(ss >> start >> priority)) {
std::cerr << "Error line " << line_num
<< ": SEQUENCE requires <start> <priority>\n";
return 1;
}
- sequences.push_back({start, priority, {}});
+ // Convert beat notation to time
+ std::string start_time = convert_to_time(start, bpm);
+
+ // Check for optional [end_time]
+ std::string end_time_str = "-1.0"; // Default: no explicit end
+ std::string optional_param;
+ if (ss >> optional_param) {
+ // Check if it's wrapped in brackets [time]
+ if (optional_param.size() >= 3 &&
+ optional_param.front() == '[' &&
+ optional_param.back() == ']') {
+ // Extract time from [time]
+ std::string time_value = optional_param.substr(1, optional_param.size() - 2);
+ end_time_str = convert_to_time(time_value, bpm);
+ } else {
+ std::cerr << "Error line " << line_num
+ << ": Optional sequence end time must be in brackets [time]\n";
+ return 1;
+ }
+ }
+
+ sequences.push_back({start_time, priority, end_time_str, {}});
current_seq = &sequences.back();
} else if (command == "EFFECT") {
if (!current_seq) {
@@ -82,18 +158,28 @@ int main(int argc, char* argv[]) {
return 1;
}
- // Capture remaining args
- std::string extra_args;
- std::getline(ss, extra_args); // Read rest of line
- // Remove leading whitespace from getline if any (getline reads the space
- // after priority)
- extra_args = trim(extra_args);
- if (!extra_args.empty()) {
- extra_args = ", " + extra_args;
+ // Convert beat notation to time
+ std::string start_time = convert_to_time(start, bpm);
+ std::string end_time = convert_to_time(end, bpm);
+
+ // Capture remaining args (but strip inline comments)
+ std::string rest_of_line;
+ std::getline(ss, rest_of_line); // Read rest of line
+ // Strip inline comments (everything from '#' onwards)
+ size_t comment_pos = rest_of_line.find('#');
+ if (comment_pos != std::string::npos) {
+ rest_of_line = rest_of_line.substr(0, comment_pos);
+ }
+ // Remove leading/trailing whitespace
+ rest_of_line = trim(rest_of_line);
+
+ std::string extra_args = "";
+ if (!rest_of_line.empty()) {
+ extra_args = ", " + rest_of_line;
}
current_seq->effects.push_back(
- {class_name, start, end, priority, extra_args});
+ {class_name, start_time, end_time, priority, extra_args});
} else {
std::cerr << "Error line " << line_num << ": Unknown command '" << command
<< "'\n";
@@ -124,12 +210,28 @@ int main(int argc, char* argv[]) {
out_file << "// Auto-generated by seq_compiler. Do not edit.\n";
out_file << "#include \"gpu/demo_effects.h\"\n";
out_file << "#include \"gpu/effect.h\"\n\n";
+
+ // Generate demo duration function
+ if (!demo_end_time.empty()) {
+ out_file << "float GetDemoDuration() {\n";
+ out_file << " return " << demo_end_time << "f;\n";
+ out_file << "}\n\n";
+ } else {
+ out_file << "float GetDemoDuration() {\n";
+ out_file << " return -1.0f; // No end time specified\n";
+ out_file << "}\n\n";
+ }
+
out_file << "void LoadTimeline(MainSequence& main_seq, WGPUDevice device, "
"WGPUQueue queue, WGPUTextureFormat format) {\n";
for (const SequenceEntry& seq : sequences) {
out_file << " {\n";
out_file << " auto seq = std::make_shared<Sequence>();\n";
+ // Set sequence end time if specified
+ if (seq.end_time != "-1.0") {
+ out_file << " seq->set_end_time(" << seq.end_time << "f);\n";
+ }
for (const EffectEntry& eff : seq.effects) {
out_file << " seq->add_effect(std::make_shared<" << eff.class_name
<< ">(device, queue, format" << eff.extra_args << "), "