diff options
Diffstat (limited to 'tools/seq_compiler.cc')
| -rw-r--r-- | tools/seq_compiler.cc | 137 |
1 files changed, 113 insertions, 24 deletions
diff --git a/tools/seq_compiler.cc b/tools/seq_compiler.cc index b61e895..3931e32 100644 --- a/tools/seq_compiler.cc +++ b/tools/seq_compiler.cc @@ -21,6 +21,7 @@ struct SequenceEntry { std::string start_time; std::string priority; std::string end_time; // Optional: -1.0f means "no explicit end" + std::string name; // Optional: human-readable name for Gantt charts std::vector<EffectEntry> effects; }; @@ -32,6 +33,15 @@ std::string trim(const std::string& str) { return str.substr(first, (last - first + 1)); } +// Calculate adaptive tick interval based on timeline duration +int calculate_tick_interval(float max_time) { + if (max_time <= 5) return 1; + if (max_time <= 40) return 2; + if (max_time <= 100) return 5; + if (max_time <= 200) return 10; + return 20; +} + // Generate ASCII Gantt chart for timeline visualization void generate_gantt_chart(const std::string& output_file, const std::vector<SequenceEntry>& sequences, @@ -67,25 +77,41 @@ void generate_gantt_chart(const std::string& output_file, } out << "\n\n"; - // Time axis header + // Time axis header with adaptive tick interval + const int tick_interval = calculate_tick_interval(max_time); out << "Time (s): "; - for (int i = 0; i <= (int)max_time; i += 5) { + for (int i = 0; i <= (int)max_time; i += tick_interval) { out << i; int spacing = (i < 10) ? 4 : (i < 100) ? 3 : 2; - if (i + 5 <= max_time) { + if (i + tick_interval <= max_time) { for (int j = 0; j < spacing; ++j) out << " "; } } out << "\n"; out << " "; for (int i = 0; i < chart_width; ++i) { - if (i % 5 == 0) out << "|"; - else out << "-"; + // Check if this column aligns with any tick mark + bool is_tick = false; + for (int t = 0; t <= (int)max_time; t += tick_interval) { + if (std::abs(i - (int)(t * time_scale)) < 1) { + is_tick = true; + break; + } + } + out << (is_tick ? "|" : "-"); } out << "\n\n"; + // Sort sequences by start time for better readability + std::vector<SequenceEntry> sorted_sequences = sequences; + std::sort(sorted_sequences.begin(), sorted_sequences.end(), + [](const SequenceEntry& a, const SequenceEntry& b) { + return std::stof(a.start_time) < std::stof(b.start_time); + }); + // Draw sequences and effects - for (const auto& seq : sequences) { + for (size_t seq_idx = 0; seq_idx < sorted_sequences.size(); ++seq_idx) { + const auto& seq = sorted_sequences[seq_idx]; float seq_start = std::stof(seq.start_time); float seq_end = seq_start; // Start at sequence start @@ -100,7 +126,11 @@ void generate_gantt_chart(const std::string& output_file, } // Draw sequence bar - out << "SEQ@" << seq_start << "s [pri=" << seq.priority << "]"; + out << "SEQ@" << seq_start << "s"; + if (!seq.name.empty()) { + out << " \"" << seq.name << "\""; + } + out << " [pri=" << seq.priority << "]"; if (seq.end_time != "-1.0") { out << " [END=" << seq_end << "s]"; } @@ -146,7 +176,17 @@ void generate_gantt_chart(const std::string& output_file, } out << " (" << eff_start << "-" << eff_end << "s)\n"; } - out << "\n"; + + // Add separator between sequences + if (seq_idx < sorted_sequences.size() - 1) { + out << " "; + for (int i = 0; i < chart_width; ++i) { + out << "─"; + } + out << "\n\n"; + } else { + out << "\n"; + } } out << "==============================================================================\n"; @@ -227,13 +267,14 @@ void generate_gantt_html(const std::string& output_file, out << "<svg width=\"" << svg_width << "\" height=\"" << svg_height << "\" xmlns=\"http://www.w3.org/2000/svg\">\n"; - // Draw time axis + // Draw time axis with adaptive tick interval + const int tick_interval = calculate_tick_interval(max_time); out << " <!-- Time axis -->\n"; out << " <line x1=\"" << margin_left << "\" y1=\"" << margin_top - 10 << "\" x2=\"" << (svg_width - 50) << "\" y2=\"" << margin_top - 10 << "\" class=\"axis-line\"/>\n"; - for (int t = 0; t <= (int)max_time; t += 5) { + for (int t = 0; t <= (int)max_time; t += tick_interval) { int x = margin_left + (int)(t * time_scale); out << " <line x1=\"" << x << "\" y1=\"" << margin_top - 15 << "\" x2=\"" << x << "\" y2=\"" << margin_top - 5 @@ -246,9 +287,17 @@ void generate_gantt_html(const std::string& output_file, << "\" class=\"time-marker\"/>\n"; } + // Sort sequences by start time for better readability + std::vector<SequenceEntry> sorted_sequences = sequences; + std::sort(sorted_sequences.begin(), sorted_sequences.end(), + [](const SequenceEntry& a, const SequenceEntry& b) { + return std::stof(a.start_time) < std::stof(b.start_time); + }); + // Draw sequences and effects int y_offset = margin_top; - for (const auto& seq : sequences) { + for (size_t seq_idx = 0; seq_idx < sorted_sequences.size(); ++seq_idx) { + const auto& seq = sorted_sequences[seq_idx]; float seq_start = std::stof(seq.start_time); float seq_end = seq_start; // Start at sequence start @@ -268,13 +317,21 @@ void generate_gantt_html(const std::string& output_file, out << " <rect x=\"" << x1 << "\" y=\"" << y_offset << "\" width=\"" << (x2 - x1) << "\" height=\"" << row_height << "\" class=\"sequence-bar\">\n"; - out << " <title>SEQ@" << seq_start << "s [pri=" << seq.priority << "] (" + out << " <title>SEQ@" << seq_start << "s"; + if (!seq.name.empty()) { + out << " \"" << seq.name << "\""; + } + out << " [pri=" << seq.priority << "] (" << seq_start << "-" << seq_end << "s)</title>\n"; out << " </rect>\n"; // Draw sequence label out << " <text x=\"10\" y=\"" << (y_offset + row_height / 2 + 4) - << "\" class=\"label\">SEQ@" << seq_start << "s [pri=" << seq.priority << "]</text>\n"; + << "\" class=\"label\">SEQ@" << seq_start << "s"; + if (!seq.name.empty()) { + out << " \"" << seq.name << "\""; + } + out << " [pri=" << seq.priority << "]</text>\n"; y_offset += row_height; @@ -306,6 +363,15 @@ void generate_gantt_html(const std::string& output_file, y_offset += row_height; } + + // Add separator between sequences + if (seq_idx < sorted_sequences.size() - 1) { + out << " <!-- Separator -->\n"; + out << " <line x1=\"" << margin_left << "\" y1=\"" << (y_offset + 5) + << "\" x2=\"" << (svg_width - 50) << "\" y2=\"" << (y_offset + 5) + << "\" style=\"stroke:#444444; stroke-width:1; stroke-dasharray:4,2;\"/>\n"; + y_offset += 10; // Extra spacing after separator + } } // Legend @@ -441,25 +507,48 @@ int main(int argc, char* argv[]) { // Convert beat notation to time std::string start_time = convert_to_time(start, bpm); - // Check for optional [end_time] + // Check for optional "name" and [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); + std::string seq_name = ""; // Default: no name + + // Read remaining tokens + std::string rest_of_line; + std::getline(ss, rest_of_line); + std::stringstream rest_ss(rest_of_line); + std::string token; + + while (rest_ss >> token) { + if (token.front() == '"') { + // Name in quotes: read until closing quote + std::string name_part = token.substr(1); // Remove opening quote + if (name_part.back() == '"') { + // Complete name in single token + name_part.pop_back(); // Remove closing quote + seq_name = name_part; + } else { + // Multi-word name: read until closing quote + seq_name = name_part; + while (rest_ss >> token) { + if (token.back() == '"') { + token.pop_back(); // Remove closing quote + seq_name += " " + token; + break; + } + seq_name += " " + token; + } + } + } else if (token.front() == '[' && token.back() == ']') { + // End time in brackets [time] + std::string time_value = token.substr(1, token.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"; + << ": Unexpected token '" << token << "'. Expected \"name\" or [end_time]\n"; return 1; } } - sequences.push_back({start_time, priority, end_time_str, {}}); + sequences.push_back({start_time, priority, end_time_str, seq_name, {}}); current_seq = &sequences.back(); } else if (command == "EFFECT") { if (!current_seq) { |
