diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-05 00:15:00 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-05 00:15:00 +0100 |
| commit | 873fa985bb4b3ec3841fa77adc16a99184cb9507 (patch) | |
| tree | de047f4045c81314327c20d85c00e552640874d2 | |
| parent | 458b00d254f5e3b1fece6e57462769ce43c96a72 (diff) | |
feat: Replace explicit priorities with stack-based priority modifiers
Simplifies effect priority management by using relative modifiers instead
of explicit numbers, making timeline reordering much more practical.
## New Priority System
Effects now use priority modifiers after EFFECT keyword:
- `+` increment priority by 1 (or start at 0 if first)
- `=` keep same priority as previous effect
- `-` decrement priority (or start at -1 if first, for background)
Old syntax:
```
EFFECT FlashEffect 0.0 0.5 0
EFFECT FadeEffect 0.1 0.3 1
EFFECT BgCube 0.2 3 -1
```
New syntax:
```
EFFECT - BgCube 0.2 3 # Priority -1 (background)
EFFECT + FlashEffect 0.0 0.5 # Priority 0
EFFECT + FadeEffect 0.1 0.3 # Priority 1
```
## Benefits
✓ Reordering effects no longer requires renumbering all priorities
✓ Priority relationships are explicit and relative
✓ File order matches render order (easier to understand)
✓ Same-priority effects clearly marked with `=`
✓ Background layers (-1) clearly marked with `-`
✓ Reduces errors when reorganizing timelines
## Implementation
- Updated seq_compiler to parse +/=/- modifiers
- Tracks current priority per sequence
- First effect sets base priority (0 or -1)
- Subsequent effects modify relative to previous
- Generated C++ code unchanged (still uses integer priorities)
## Changes to demo.seq
- All effects updated to use new syntax
- Effects reordered by priority within sequences
- Priority gaps removed (were likely unintentional)
- Comments updated to reflect new system
## Documentation
- Updated SEQUENCE.md with new syntax
- Added examples showing +, =, - usage
- Explained priority calculation rules
This makes timeline authoring significantly more maintainable, especially
when experimenting with different effect orderings during development.
| -rw-r--r-- | assets/demo.seq | 110 | ||||
| -rw-r--r-- | doc/SEQUENCE.md | 53 | ||||
| -rw-r--r-- | src/generated/timeline.cc | 26 | ||||
| -rw-r--r-- | tools/seq_compiler.cc | 45 |
4 files changed, 147 insertions, 87 deletions
diff --git a/assets/demo.seq b/assets/demo.seq index 35935a7..44df234 100644 --- a/assets/demo.seq +++ b/assets/demo.seq @@ -8,10 +8,10 @@ # # QUICK REFERENCE: # SEQUENCE <start> <priority> [optional_end] -# EFFECT <ClassName> <start> <end> <priority> +# EFFECT <+|=|-> <ClassName> <start> <end> # +# Priority modifiers: + (increment), = (same), - (decrement/background) # Time notation: 0b (beats), 0.0 (seconds) -# Priority: Higher numbers render later (on top) # # VALIDATION & VISUALIZATION: # ./build/seq_compiler assets/demo.seq # Validate only @@ -19,86 +19,88 @@ # # ============================================================================ +# BPM 120 + SEQUENCE 0b 0 - EFFECT FlashEffect 0.0 1. 0 - EFFECT FadeEffect 0.1 1. 1 # Add fade - EFFECT FlashCubeEffect .2 3 -1 # Background cube (priority -1 = behind everything) - EFFECT SolarizeEffect 0 4b 3 # Color inversion (last) + EFFECT - FlashCubeEffect .2 3 # Background cube (priority -1 = behind everything) + EFFECT + FlashEffect 0.0 1. # Priority 0 + EFFECT + FadeEffect 0.1 1. # Priority 1 + EFFECT + SolarizeEffect 0 4b # Priority 2 (was 3, now contiguous) SEQUENCE 4b 0 - EFFECT FlashEffect 0.0 0.2 4 # Add flash after solarize - EFFECT FlashCubeEffect 0.1 3. -1 + EFFECT - FlashCubeEffect 0.1 3. # Priority -1 + EFFECT + FlashEffect 0.0 0.2 # Priority 0 (was 4, now contiguous) SEQUENCE 6b 1 - EFFECT ParticlesEffect 0 4 1 # Particles layer - EFFECT GaussianBlurEffect 0 8 1 # Blur + EFFECT + ParticlesEffect 0 4 # Priority 0 + EFFECT = GaussianBlurEffect 0 8 # Priority 0 (same layer) SEQUENCE 7b 0 - EFFECT FadeEffect 0.1 1.0 5 # Add fade - EFFECT HeptagonEffect 0.0 .2 0 # Main geometric effect + EFFECT + HeptagonEffect 0.0 .2 # Priority 0 + EFFECT + FadeEffect 0.1 1.0 # Priority 1 (was 5, now contiguous) # Post-processing chain (priority 10 = applied after scene rendering) # Effects are applied in priority order: lower numbers first SEQUENCE 8b 3 - EFFECT ThemeModulationEffect 0 4 0 # Brightness modulation (first) - EFFECT HeptagonEffect 0.0 4.0 0 # Main geometric effect - EFFECT GaussianBlurEffect 0 8 1 # Blur - EFFECT ChromaAberrationEffect 0 6 2 # Color separation - EFFECT SolarizeEffect 0 10 3 # Color inversion (last) + EFFECT + ThemeModulationEffect 0 4 # Priority 0 + EFFECT = HeptagonEffect 0.0 4.0 # Priority 0 (same layer) + EFFECT + GaussianBlurEffect 0 8 # Priority 1 + EFFECT + ChromaAberrationEffect 0 6 # Priority 2 + EFFECT + SolarizeEffect 0 10 # Priority 3 SEQUENCE 12b 2 - EFFECT FlashCubeEffect .2 3 -1 # Background cube (priority -1 = behind everything) - EFFECT HeptagonEffect 0 4 0 - EFFECT ParticlesEffect 0 4 1 # Particles layer + EFFECT - FlashCubeEffect .2 3 # Priority -1 (background) + EFFECT + HeptagonEffect 0 4 # Priority 0 + EFFECT + ParticlesEffect 0 4 # Priority 1 SEQUENCE 15b 2 - EFFECT FlashCubeEffect .2 3 -1 # Background cube (priority -1 = behind everything) - EFFECT FlashEffect 0.0 1 0 + EFFECT - FlashCubeEffect .2 3 # Priority -1 (background) + EFFECT + FlashEffect 0.0 1 # Priority 0 SEQUENCE 16b 10 - EFFECT FlashCubeEffect .2 3 -1 # Background cube (priority -1 = behind everything) - EFFECT GaussianBlurEffect 0 8 1 # Blur - EFFECT FlashEffect 0.0 0.2 4 # Add flash after solarize - EFFECT FlashEffect 1b 0.2 4 # Add flash after solarize + EFFECT - FlashCubeEffect .2 3 # Priority -1 (background) + EFFECT + GaussianBlurEffect 0 8 # Priority 0 + EFFECT + FlashEffect 0.0 0.2 # Priority 1 + EFFECT = FlashEffect 1b 0.2 # Priority 1 (same layer) SEQUENCE 17b 2 - EFFECT ThemeModulationEffect 0 4 0 # Brightness modulation (first) - EFFECT HeptagonEffect 0.2 2.0 1 # Main geometric effect - EFFECT ParticlesEffect 0 4 1 # Particles layer - EFFECT GaussianBlurEffect 0 8 3 # Blur - EFFECT Hybrid3DEffect 0 4 2 # 3D objects (priority 2 = foreground) - EFFECT ChromaAberrationEffect 0 6 4 # Color separation + EFFECT + ThemeModulationEffect 0 4 # Priority 0 + EFFECT + HeptagonEffect 0.2 2.0 # Priority 1 + EFFECT = ParticlesEffect 0 4 # Priority 1 (same layer) + EFFECT + Hybrid3DEffect 0 4 # Priority 2 + EFFECT + GaussianBlurEffect 0 8 # Priority 3 + EFFECT + ChromaAberrationEffect 0 6 # Priority 4 SEQUENCE 24b 1 - EFFECT ThemeModulationEffect 0 8 0 # Brightness modulation (first) - EFFECT HeptagonEffect 0.2 2.0 1 # Main geometric effect - EFFECT Hybrid3DEffect 0 20 2 # 3D objects (priority 2 = foreground) - EFFECT GaussianBlurEffect 0 8 3 # Blur - EFFECT ChromaAberrationEffect 0 10 4 # Color separation - EFFECT SolarizeEffect 0 10 5 # Color inversion (last) + EFFECT + ThemeModulationEffect 0 8 # Priority 0 + EFFECT + HeptagonEffect 0.2 2.0 # Priority 1 + EFFECT + Hybrid3DEffect 0 20 # Priority 2 + EFFECT + GaussianBlurEffect 0 8 # Priority 3 + EFFECT + ChromaAberrationEffect 0 10 # Priority 4 + EFFECT + SolarizeEffect 0 10 # Priority 5 SEQUENCE 32b 0 - EFFECT ThemeModulationEffect 0 4 0 # Brightness modulation (first) - EFFECT HeptagonEffect 0 16 1 # Main geometric effect - EFFECT ChromaAberrationEffect 0 16 3 # Color separation - EFFECT GaussianBlurEffect 0 8 4 # Blur + EFFECT + ThemeModulationEffect 0 4 # Priority 0 + EFFECT + HeptagonEffect 0 16 # Priority 1 + EFFECT + ChromaAberrationEffect 0 16 # Priority 2 + EFFECT + GaussianBlurEffect 0 8 # Priority 3 SEQUENCE 48b 0 - EFFECT ThemeModulationEffect 0 4 0 # Brightness modulation (first) - EFFECT HeptagonEffect 0.2 2.0 1 # Main geometric effect - EFFECT GaussianBlurEffect 0 8 3 # Blur - EFFECT SolarizeEffect 0 2 5 # Color inversion (last) + EFFECT + ThemeModulationEffect 0 4 # Priority 0 + EFFECT + HeptagonEffect 0.2 2.0 # Priority 1 + EFFECT + GaussianBlurEffect 0 8 # Priority 2 + EFFECT + SolarizeEffect 0 2 # Priority 3 SEQUENCE 56b 0 - EFFECT ThemeModulationEffect 0 8 0 # Brightness modulation (first) - EFFECT HeptagonEffect 0.2 2.0 0 # Main geometric effect - EFFECT Hybrid3DEffect 0 4 1 # 3D objects (priority 2 = foreground) - EFFECT HeptagonEffect 0 16 2 # Main geometric effect - EFFECT ChromaAberrationEffect 0 16 3 # Color separation - EFFECT GaussianBlurEffect 0 8 4 # Blur + EFFECT + ThemeModulationEffect 0 8 # Priority 0 + EFFECT = HeptagonEffect 0.2 2.0 # Priority 0 (same layer) + EFFECT + Hybrid3DEffect 0 4 # Priority 1 + EFFECT + HeptagonEffect 0 16 # Priority 2 + EFFECT + ChromaAberrationEffect 0 16 # Priority 3 + EFFECT + GaussianBlurEffect 0 8 # Priority 4 SEQUENCE 62b 0 - EFFECT ThemeModulationEffect 0 3 0 # Brightness modulation (first) - EFFECT SolarizeEffect 0 3 5 # Color inversion (last) + EFFECT + ThemeModulationEffect 0 3 # Priority 0 + EFFECT + SolarizeEffect 0 3 # Priority 1 # Demo automatically exits at this time (supports beat notation) END_DEMO 65b diff --git a/doc/SEQUENCE.md b/doc/SEQUENCE.md index 05cdc93..614339e 100644 --- a/doc/SEQUENCE.md +++ b/doc/SEQUENCE.md @@ -79,17 +79,26 @@ SEQUENCE <global_start> <priority> [optional_end] ### EFFECT Declaration ``` -EFFECT <EffectClassName> <local_start> <local_end> <priority> [constructor_args...] +EFFECT <+|=|-> <EffectClassName> <local_start> <local_end> [constructor_args...] ``` **Parameters:** +- Priority modifier (one of): + - `+`: Increment priority (or start at 0 if first effect) + - `=`: Keep same priority as previous effect + - `-`: Decrement priority (or start at -1 if first effect, for background layers) - `EffectClassName`: C++ class name (must be declared in `demo_effects.h`) - `local_start`: Start time relative to sequence start (beats or seconds) - `local_end`: End time relative to sequence start (beats or seconds) -- `priority`: Render order within sequence (lower = drawn first/background) - - Negative priorities draw behind everything - `constructor_args`: Optional additional parameters (rarely used) +**Priority System:** +- Effects are assigned priorities based on their order in the file +- First effect: `+` starts at 0, `-` starts at -1, `=` starts at 0 +- Subsequent effects: `+` increments, `=` keeps same, `-` decrements +- Priorities determine render order (lower = drawn first/background) +- Effects should be listed in desired priority order within each sequence + --- ## Time Notation @@ -223,36 +232,46 @@ White flash on strong beat hits. ### Basic Sequence ``` SEQUENCE 0 0 - EFFECT FlashEffect 0.0 0.5 1 # Starts immediately, runs 0.5s, priority 1 - EFFECT HeptagonEffect 0.2 10 0 # Starts at 0.2s, runs until 10s, priority 0 + EFFECT + FlashEffect 0.0 0.5 # Priority 0 (first with +) + EFFECT + HeptagonEffect 0.2 10 # Priority 1 (increment) +``` + +### Same Priority (Layered Effects) +``` +SEQUENCE 0 0 + EFFECT + Flash 0.0 0.5 # Priority 0 + EFFECT = Fade 0.1 0.3 # Priority 0 (same as Flash) + EFFECT + Other 0.2 3 # Priority 1 (increment) +``` + +### Background Elements +``` +SEQUENCE 0 0 + EFFECT - FlashCube 0 10 # Priority -1 (background) + EFFECT = BgEffect 0 5 # Priority -1 (same layer) + EFFECT + MainEffect 0 10 # Priority 0 (foreground) ``` ### Sequence with Explicit End Time ``` SEQUENCE 8b 0 [5.0] - EFFECT ParticlesEffect 0 120 1 # Would run 120s, but sequence ends at 5s + EFFECT + Particles 0 120 # Would run 120s, but sequence ends at 5s ``` ### Post-Processing Chain ``` SEQUENCE 0 10 - EFFECT GaussianBlurEffect 0 60 1 # Applied first - EFFECT ChromaAberrationEffect 0 60 2 # Applied second - EFFECT SolarizeEffect 0 60 3 # Applied last -``` - -### Background Element -``` -SEQUENCE 0 0 - EFFECT FlashCubeEffect 0 10 -1 # priority -1 = background layer + EFFECT + GaussianBlur 0 60 # Priority 0 (applied first) + EFFECT + ChromaAberration 0 60 # Priority 1 (applied second) + EFFECT + Solarize 0 60 # Priority 2 (applied last) ``` ### Music-Synchronized Effects ``` # BPM 120 SEQUENCE 0b 0 # Start at beat 0 (0.0s) - EFFECT FlashEffect 0b 1b 1 # Flash from beat 0 to beat 1 (0-0.5s) - EFFECT HeptagonEffect 4b 8b 0 # Main effect from beat 4 to 8 (2-4s) + EFFECT + Flash 0b 1b # Flash from beat 0 to beat 1 (0-0.5s) + EFFECT + Heptagon 4b 8b # Main effect from beat 4 to 8 (2-4s) ``` --- diff --git a/src/generated/timeline.cc b/src/generated/timeline.cc index 381c403..0b69b09 100644 --- a/src/generated/timeline.cc +++ b/src/generated/timeline.cc @@ -12,35 +12,35 @@ void LoadTimeline(MainSequence& main_seq, WGPUDevice device, WGPUQueue queue, WG seq->add_effect(std::make_shared<FlashCubeEffect>(device, queue, format), .2f, 1.500000f, -1); seq->add_effect(std::make_shared<FlashEffect>(device, queue, format), 0.0f, 1.f, 0); seq->add_effect(std::make_shared<FadeEffect>(device, queue, format), 0.1f, 1.f, 1); - seq->add_effect(std::make_shared<SolarizeEffect>(device, queue, format), 0.000000f, 2.000000f, 3); + seq->add_effect(std::make_shared<SolarizeEffect>(device, queue, format), 0.000000f, 2.000000f, 2); main_seq.add_sequence(seq, 0.000000f, 0); } { auto seq = std::make_shared<Sequence>(); seq->add_effect(std::make_shared<FlashCubeEffect>(device, queue, format), 0.1f, 3.f, -1); - seq->add_effect(std::make_shared<FlashEffect>(device, queue, format), 0.0f, 0.2f, 4); + seq->add_effect(std::make_shared<FlashEffect>(device, queue, format), 0.0f, 0.2f, 0); main_seq.add_sequence(seq, 2.000000f, 0); } { auto seq = std::make_shared<Sequence>(); seq->add_effect(std::make_shared<HeptagonEffect>(device, queue, format), 0.0f, .2f, 0); - seq->add_effect(std::make_shared<FadeEffect>(device, queue, format), 0.1f, 1.0f, 5); + seq->add_effect(std::make_shared<FadeEffect>(device, queue, format), 0.1f, 1.0f, 1); main_seq.add_sequence(seq, 3.500000f, 0); } { auto seq = std::make_shared<Sequence>(); seq->add_effect(std::make_shared<ThemeModulationEffect>(device, queue, format), 0.000000f, 2.000000f, 0); seq->add_effect(std::make_shared<HeptagonEffect>(device, queue, format), 0.000000f, 8.000000f, 1); - seq->add_effect(std::make_shared<ChromaAberrationEffect>(device, queue, format), 0.000000f, 8.000000f, 3); - seq->add_effect(std::make_shared<GaussianBlurEffect>(device, queue, format), 0.000000f, 4.000000f, 4); + seq->add_effect(std::make_shared<ChromaAberrationEffect>(device, queue, format), 0.000000f, 8.000000f, 2); + seq->add_effect(std::make_shared<GaussianBlurEffect>(device, queue, format), 0.000000f, 4.000000f, 3); main_seq.add_sequence(seq, 16.000000f, 0); } { auto seq = std::make_shared<Sequence>(); seq->add_effect(std::make_shared<ThemeModulationEffect>(device, queue, format), 0.000000f, 2.000000f, 0); seq->add_effect(std::make_shared<HeptagonEffect>(device, queue, format), 0.2f, 2.0f, 1); - seq->add_effect(std::make_shared<GaussianBlurEffect>(device, queue, format), 0.000000f, 4.000000f, 3); - seq->add_effect(std::make_shared<SolarizeEffect>(device, queue, format), 0.000000f, 1.000000f, 5); + seq->add_effect(std::make_shared<GaussianBlurEffect>(device, queue, format), 0.000000f, 4.000000f, 2); + seq->add_effect(std::make_shared<SolarizeEffect>(device, queue, format), 0.000000f, 1.000000f, 3); main_seq.add_sequence(seq, 24.000000f, 0); } { @@ -56,13 +56,13 @@ void LoadTimeline(MainSequence& main_seq, WGPUDevice device, WGPUQueue queue, WG { auto seq = std::make_shared<Sequence>(); seq->add_effect(std::make_shared<ThemeModulationEffect>(device, queue, format), 0.000000f, 1.500000f, 0); - seq->add_effect(std::make_shared<SolarizeEffect>(device, queue, format), 0.000000f, 1.500000f, 5); + seq->add_effect(std::make_shared<SolarizeEffect>(device, queue, format), 0.000000f, 1.500000f, 1); main_seq.add_sequence(seq, 31.000000f, 0); } { auto seq = std::make_shared<Sequence>(); - seq->add_effect(std::make_shared<ParticlesEffect>(device, queue, format), 0.000000f, 2.000000f, 1); - seq->add_effect(std::make_shared<GaussianBlurEffect>(device, queue, format), 0.000000f, 4.000000f, 1); + seq->add_effect(std::make_shared<ParticlesEffect>(device, queue, format), 0.000000f, 2.000000f, 0); + seq->add_effect(std::make_shared<GaussianBlurEffect>(device, queue, format), 0.000000f, 4.000000f, 0); main_seq.add_sequence(seq, 3.000000f, 1); } { @@ -110,9 +110,9 @@ void LoadTimeline(MainSequence& main_seq, WGPUDevice device, WGPUQueue queue, WG { auto seq = std::make_shared<Sequence>(); seq->add_effect(std::make_shared<FlashCubeEffect>(device, queue, format), .2f, 1.500000f, -1); - seq->add_effect(std::make_shared<GaussianBlurEffect>(device, queue, format), 0.000000f, 4.000000f, 1); - seq->add_effect(std::make_shared<FlashEffect>(device, queue, format), 0.0f, 0.2f, 4); - seq->add_effect(std::make_shared<FlashEffect>(device, queue, format), 0.500000f, 0.2f, 4); + seq->add_effect(std::make_shared<GaussianBlurEffect>(device, queue, format), 0.000000f, 4.000000f, 0); + seq->add_effect(std::make_shared<FlashEffect>(device, queue, format), 0.0f, 0.2f, 1); + seq->add_effect(std::make_shared<FlashEffect>(device, queue, format), 0.500000f, 0.2f, 1); main_seq.add_sequence(seq, 8.000000f, 10); } } diff --git a/tools/seq_compiler.cc b/tools/seq_compiler.cc index 45cfc1a..7ac921f 100644 --- a/tools/seq_compiler.cc +++ b/tools/seq_compiler.cc @@ -467,13 +467,52 @@ int main(int argc, char* argv[]) { << ": EFFECT found outside of SEQUENCE\n"; return 1; } - std::string class_name, start, end, priority; - if (!(ss >> class_name >> start >> end >> priority)) { + std::string priority_mod, class_name, start, end; + if (!(ss >> priority_mod >> class_name >> start >> end)) { std::cerr << "Error line " << line_num - << ": EFFECT requires <Class> <start> <end> <priority>\n"; + << ": EFFECT requires <+|=|-> <Class> <start> <end>\n"; return 1; } + // Validate priority modifier + if (priority_mod != "+" && priority_mod != "=" && priority_mod != "-") { + std::cerr << "Error line " << line_num + << ": Priority modifier must be '+', '=', or '-', got: " << priority_mod << "\n"; + return 1; + } + + // Calculate priority based on modifier and sequence state + static int current_priority = 0; + static bool first_in_sequence = true; + static const SequenceEntry* last_seq = nullptr; + + // Reset priority tracking for new sequence + if (current_seq != last_seq) { + current_priority = 0; + first_in_sequence = true; + last_seq = current_seq; + } + + // Handle first effect in sequence + if (first_in_sequence) { + if (priority_mod == "-") { + current_priority = -1; // Background layer + } else { + current_priority = 0; // Default start (+ or =) + } + first_in_sequence = false; + } else { + // Update priority based on modifier for subsequent effects + if (priority_mod == "+") { + current_priority++; + } else if (priority_mod == "-") { + current_priority--; + } + // '=' keeps current_priority unchanged + } + + std::string priority = std::to_string(current_priority); + // Convert beat notation to time std::string start_time = convert_to_time(start, bpm); std::string end_time = convert_to_time(end, bpm); |
