summaryrefslogtreecommitdiff
path: root/ANALYSIS_VARIABLE_TEMPO_V2.md
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-05 02:01:57 +0100
committerskal <pascal.massimino@gmail.com>2026-02-05 02:01:57 +0100
commit93a65b43094641b4c188b4fc260b8ed44c883728 (patch)
tree93480071658129c06fe43d72e9235fc3ed10bbda /ANALYSIS_VARIABLE_TEMPO_V2.md
parentefcfce7a88bcf369d6c39564320b8c026554572b (diff)
move MD filesHEADmain
Diffstat (limited to 'ANALYSIS_VARIABLE_TEMPO_V2.md')
-rw-r--r--ANALYSIS_VARIABLE_TEMPO_V2.md414
1 files changed, 0 insertions, 414 deletions
diff --git a/ANALYSIS_VARIABLE_TEMPO_V2.md b/ANALYSIS_VARIABLE_TEMPO_V2.md
deleted file mode 100644
index add347c..0000000
--- a/ANALYSIS_VARIABLE_TEMPO_V2.md
+++ /dev/null
@@ -1,414 +0,0 @@
-# Variable Tempo: Simplified Approach (V2)
-
-## User's Proposal: Trigger Timing Only
-
-**Key Insight:** Don't change spectrograms or playback speed - just change **when** they trigger!
-
-### The Simple Solution
-
-```cpp
-// In main loop
-static float music_time = 0.0f;
-static float tempo_scale = 1.0f; // Can be animated/changed
-
-void update_game_logic(float dt) {
- // Music time advances at variable rate
- music_time += dt * tempo_scale;
-
- // Patterns trigger based on music_time (not physical time)
- tracker_update(music_time);
-}
-```
-
-**That's it!** 🎉
-
-### What This Achieves
-
-**Drums, melodies, samples:** All sound identical (no pitch shift)
-**Tempo changes:** Patterns trigger faster/slower based on `tempo_scale`
-**No synth changes:** Playback rate stays at 32kHz (unchanged)
-
-### Example Timeline
-
-**Pattern triggers at music_time = 4.0**
-
-| tempo_scale | Physical Time | Effect |
-|-------------|---------------|--------|
-| 1.0 | 4.0s | Normal tempo |
-| 2.0 | 2.0s | Triggers 2x earlier (accelerated) |
-| 0.5 | 8.0s | Triggers 2x later (slowed) |
-
-**Visual:**
-```
-Physical Time: 0s----1s----2s----3s----4s----5s----6s----7s----8s
- ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
-
-tempo_scale=1.0: 🥁 (triggers at 4s)
-
-tempo_scale=2.0: 🥁 (triggers at 2s - accelerated!)
-
-tempo_scale=0.5: 🥁 (triggers at 8s - slowed)
-```
-
-### The "Reset" Trick
-
-**Problem:** Music has accelerated to 2.0x, feels too fast
-**Solution:** Reset tempo and switch to denser pattern
-
-```cpp
-// Music accelerating
-tempo_scale = 1.0 + t * 0.1; // Gradually speeds up
-
-// At some point (e.g., tempo_scale = 2.0)
-if (tempo_scale >= 2.0) {
- tempo_scale = 1.0; // Reset to normal
- trigger_pattern_dense(); // Switch to 2x denser pattern
-}
-```
-
-**Pattern Authoring:**
-```
-Pattern A (sparse): [kick]---[snare]---[kick]---[snare]---
- beat 0 beat 1 beat 2 beat 3
-
-Pattern B (dense): [kick]-[snare]-[kick]-[snare]-
- beat 0 beat 0.5 beat 1 beat 1.5
-```
-
-**Result:** Music feels the same tempo, but you've "reset" the timeline!
-
----
-
-## What Needs to Change in Current Code
-
-### Change 1: Main Loop (main.cc)
-
-**Current:**
-```cpp
-void update_game_logic(double t) {
- tracker_update((float)t); // ❌ Uses physical time directly
-}
-```
-
-**New:**
-```cpp
-static float g_music_time = 0.0f;
-static float g_tempo_scale = 1.0f;
-
-void update_game_logic(double t) {
- float dt = get_delta_time(); // Physical time delta
-
- // Music time advances at variable rate
- g_music_time += dt * g_tempo_scale;
-
- tracker_update(g_music_time); // ✅ Uses music time
-}
-```
-
-### Change 2: Tempo Control API (NEW)
-
-```cpp
-// In tracker.h or main.cc
-void set_tempo_scale(float scale);
-float get_tempo_scale();
-float get_music_time();
-```
-
-### Change 3: Tracker (NO CHANGES NEEDED!)
-
-**tracker.h:** Keep as-is
-**tracker.cc:** Keep as-is
-**TrackerScore.bpm:** Keep it! (used for compositing patterns)
-
-The tracker already works with abstract "time" - we just feed it `music_time` instead of physical time.
-
-### Change 4: Synth (NO CHANGES NEEDED!)
-
-Spectrograms play back at fixed rate (32kHz).
-No pitch shifting, no interpolation needed.
-
----
-
-## Detailed Example: Accelerating Drum Beat
-
-### Setup
-```cpp
-// Pattern: kick on beats 0 and 2, snare on beats 1 and 3
-TrackerEvent drum_events[] = {
- {0.0f, KICK_ID, 1.0f, 0.0f}, // Beat 0
- {1.0f, SNARE_ID, 0.9f, 0.0f}, // Beat 1
- {2.0f, KICK_ID, 1.0f, 0.0f}, // Beat 2
- {3.0f, SNARE_ID, 0.9f, 0.0f}, // Beat 3
-};
-
-TrackerPattern drum_pattern = {drum_events, 4, 4.0f};
-```
-
-### Scenario: Gradual Acceleration
-
-```cpp
-// Main loop
-float tempo_scale = 1.0f;
-
-void update_game_logic(float dt) {
- // Gradually accelerate (0.05x faster per second)
- tempo_scale += dt * 0.05f;
-
- music_time += dt * tempo_scale;
- tracker_update(music_time);
-}
-```
-
-**Timeline:**
-```
-Physical Time: 0s 1s 2s 3s 4s 5s 6s 7s 8s
-tempo_scale: 1.0 1.05 1.10 1.15 1.20 1.25 1.30 1.35 1.40
-
-Music Time: 0.0 1.05 2.15 3.30 4.50 5.75 7.05 8.40 9.80
- ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
-Pattern Trigs: 🥁 🥁 🥁 🥁 🥁 🥁 🥁 🥁 🥁
-(every 4 beats) 0 4 8 12 16 20 24 28 32
-
-Physical times when patterns trigger:
-- Pattern 0: t=0.0s
-- Pattern 1: t≈3.8s (instead of 4.0s)
-- Pattern 2: t≈7.2s (instead of 8.0s)
-- Pattern 3: t≈10.2s (instead of 12.0s)
-```
-
-**Effect:** Drum beat gradually feels faster, even though drums sound the same!
-
----
-
-## The "Reset" Strategy
-
-### Problem
-After accelerating to 2.0x, music feels too rushed. Want to maintain energy but reset tempo.
-
-### Solution: Tempo Reset + Pattern Swap
-
-**Before Reset:**
-- tempo_scale = 2.0
-- Pattern A (sparse): kicks every 1 beat
-
-**After Reset:**
-- tempo_scale = 1.0
-- Pattern B (dense): kicks every 0.5 beats
-
-**Result:** Same physical rate of kicks, but tempo has "reset"!
-
-### Code Example
-
-```cpp
-void update_game_logic(float dt) {
- music_time += dt * tempo_scale;
-
- // Gradually accelerate
- tempo_scale += dt * 0.1f;
-
- // Check for reset point
- if (tempo_scale >= 2.0f) {
- // Reset tempo
- tempo_scale = 1.0f;
-
- // Switch to denser pattern
- current_pattern_density *= 2; // 2x more events per beat
-
- // Optionally: retrigger current section with new density
- retrigger_section_with_density(current_pattern_density);
- }
-
- tracker_update(music_time);
-}
-```
-
-### Pattern Authoring Strategy
-
-**Create patterns at multiple densities:**
-
-```cpp
-// Sparse pattern (quarter notes)
-TrackerEvent pattern_1x[] = {
- {0.0f, KICK, 1.0f, 0.0f},
- {1.0f, SNARE, 0.9f, 0.0f},
- {2.0f, KICK, 1.0f, 0.0f},
- {3.0f, SNARE, 0.9f, 0.0f},
-};
-
-// Dense pattern (eighth notes)
-TrackerEvent pattern_2x[] = {
- {0.0f, KICK, 1.0f, 0.0f},
- {0.5f, HIHAT, 0.6f, 0.0f},
- {1.0f, SNARE, 0.9f, 0.0f},
- {1.5f, HIHAT, 0.6f, 0.0f},
- {2.0f, KICK, 1.0f, 0.0f},
- {2.5f, HIHAT, 0.6f, 0.0f},
- {3.0f, SNARE, 0.9f, 0.0f},
- {3.5f, HIHAT, 0.6f, 0.0f},
-};
-
-// Very dense pattern (sixteenth notes)
-TrackerEvent pattern_4x[] = {
- // ... even more events
-};
-```
-
-**Use pattern density to match tempo:**
-- tempo_scale = 1.0x → use pattern_1x
-- tempo_scale = 2.0x → reset to 1.0x, use pattern_2x
-- tempo_scale = 4.0x → reset to 1.0x, use pattern_4x
-
----
-
-## Comparison: Old Proposal vs. New Proposal
-
-| Aspect | Old Proposal (Complex) | New Proposal (Simple) |
-|--------|------------------------|----------------------|
-| **Synth Changes** | Variable playback speed, interpolation | ❌ None |
-| **Pitch Shifting** | Yes (side effect) | ❌ No |
-| **Spectrograms** | Modified at playback | ✅ Unchanged |
-| **Complexity** | High (12 hours) | Low (1 hour) |
-| **Code Changes** | ~500 lines | ~20 lines |
-| **Size Impact** | +2-3 KB | +50 bytes |
-| **Quality** | Good with interpolation | ✅ Perfect (no artifacts) |
-
----
-
-## Implementation Checklist
-
-### Step 1: Add Music Time State (5 minutes)
-```cpp
-// In main.cc (global scope)
-static float g_music_time = 0.0f;
-static float g_tempo_scale = 1.0f;
-static float g_last_physical_time = 0.0f;
-```
-
-### Step 2: Update Main Loop (10 minutes)
-```cpp
-void update_game_logic(double physical_time) {
- // Calculate delta
- float dt = (float)(physical_time - g_last_physical_time);
- g_last_physical_time = physical_time;
-
- // Advance music time at scaled rate
- g_music_time += dt * g_tempo_scale;
-
- // Update tracker with music time (not physical time)
- tracker_update(g_music_time);
-}
-
-// In main loop
-while (!should_close) {
- double current_time = platform_state.time + seek_time;
- update_game_logic(current_time); // Pass physical time
- // ...
-}
-```
-
-### Step 3: Add Tempo Control API (10 minutes)
-```cpp
-// In main.cc or new file
-void set_tempo_scale(float scale) {
- g_tempo_scale = scale;
-}
-
-float get_tempo_scale() {
- return g_tempo_scale;
-}
-
-float get_music_time() {
- return g_music_time;
-}
-```
-
-### Step 4: Test with Simple Acceleration (10 minutes)
-```cpp
-// Temporary test: gradual acceleration
-void update_game_logic(double physical_time) {
- float dt = get_delta_time();
-
- // TEST: Accelerate from 1.0x to 2.0x over 10 seconds
- g_tempo_scale = 1.0f + (physical_time / 10.0f);
- g_tempo_scale = fminf(g_tempo_scale, 2.0f);
-
- g_music_time += dt * g_tempo_scale;
- tracker_update(g_music_time);
-}
-```
-
-### Step 5: Implement Reset Logic (15 minutes)
-```cpp
-// When tempo hits threshold, reset and switch patterns
-if (g_tempo_scale >= 2.0f) {
- g_tempo_scale = 1.0f;
- // Trigger denser pattern here
-}
-```
-
-### Step 6: Create Pattern Variants (tracker compiler work)
-- Author patterns at 1x, 2x, 4x densities
-- Map tempo ranges to pattern variants
-
----
-
-## Advantages of This Approach
-
-✅ **Simple:** ~20 lines of code
-✅ **No pitch shift:** Samples sound identical
-✅ **No synth changes:** Risk-free
-✅ **Flexible:** Easy to animate tempo curves
-✅ **Tiny size impact:** ~50 bytes
-✅ **Perfect quality:** No interpolation artifacts
-
----
-
-## Example: Tempo Curves
-
-### Linear Acceleration
-```cpp
-tempo_scale = 1.0f + t * 0.1f; // 0.1x faster per second
-```
-
-### Exponential Acceleration
-```cpp
-tempo_scale = powf(2.0f, t / 10.0f); // Doubles every 10 seconds
-```
-
-### Oscillating Tempo
-```cpp
-tempo_scale = 1.0f + 0.3f * sinf(t * 0.5f); // Wave between 0.7x and 1.3x
-```
-
-### Manual Control (BPM curve from score)
-```cpp
-// Define tempo curve in tracker score
-float tempo_curve[] = {1.0f, 1.1f, 1.3f, 1.6f, 2.0f, 1.0f, ...};
-tempo_scale = interpolate_tempo_curve(music_time);
-```
-
----
-
-## Conclusion
-
-**Your proposal is brilliant!** 🎯
-
-### What You Get
-- Variable tempo without modifying spectrograms
-- No pitch shifting (drums sound like drums)
-- Simple implementation (~1 hour)
-- Tiny code size (~50 bytes)
-- Perfect audio quality
-
-### What You Need to Do
-1. Add `g_music_time` and `g_tempo_scale` to main loop
-2. Compute `music_time += dt * tempo_scale`
-3. Pass `music_time` to `tracker_update()`
-4. Animate `tempo_scale` however you want!
-
-### For the "Reset" Trick
-- Author patterns at 1x, 2x, 4x note densities
-- When tempo hits 2.0x, reset to 1.0x and switch to denser pattern
-- Result: Same perceived tempo, but timeline has reset
-
-**Ready to implement?** This is a 1-hour task!