Documentation Index Fetch the complete documentation index at: https://mintlify.com/ivan-1f/phichain/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The BPM system manages tempo changes in charts and provides conversion between beats and real time. Phichain supports multiple BPM changes throughout a chart.
Types
BpmList
A list of BPM change points with automatic time calculation.
Vector of BPM points, sorted by beat position
BpmPoint
A single BPM change at a specific beat.
The beat position where this BPM takes effect
The tempo in beats per minute
Computed timestamp in seconds (automatically calculated, not serialized)
Creating BPM Lists
Single BPM
Multiple BPM Changes
Dynamic BPM Changes
use phichain_chart :: bpm_list :: { BpmList , BpmPoint };
use phichain_chart :: beat :: Beat ;
// Simple single-BPM chart at 120 BPM
let bpm_list = BpmList :: single ( 120.0 );
// Equivalent to:
let bpm_list = BpmList :: new ( vec! [
BpmPoint :: new ( Beat :: ZERO , 120.0 ),
]);
// Or using default (also 120 BPM):
let bpm_list = BpmList :: default ();
Beat-Time Conversion
use phichain_chart :: bpm_list :: { BpmList , BpmPoint };
use phichain_chart :: beat :: Beat ;
let bpm_list = BpmList :: new ( vec! [
BpmPoint :: new ( Beat :: ZERO , 120.0 ),
BpmPoint :: new ( Beat :: from ( 4.0 ), 240.0 ),
]);
// Convert beats to seconds
let time_0 = bpm_list . time_at ( Beat :: ZERO ); // 0.0s
let time_1 = bpm_list . time_at ( Beat :: ONE ); // 0.5s (60s/120bpm)
let time_2 = bpm_list . time_at ( Beat :: from ( 2.0 )); // 1.0s
let time_4 = bpm_list . time_at ( Beat :: from ( 4.0 )); // 2.0s
let time_5 = bpm_list . time_at ( Beat :: from ( 5.0 )); // 2.25s (at 240 BPM)
let time_8 = bpm_list . time_at ( Beat :: from ( 8.0 )); // 3.0s
Beat Normalization
Normalization converts beats from a variable-BPM chart to a constant-BPM timeline:
Normalize Beats
Use Case: Exporting
use phichain_chart :: bpm_list :: { BpmList , BpmPoint };
use phichain_chart :: beat :: { Beat , beat};
let bpm_list = BpmList :: new ( vec! [
BpmPoint :: new ( beat! ( 0 ), 120.0 ),
BpmPoint :: new ( beat! ( 4 ), 240.0 ),
]);
// Normalize to 120 BPM timeline
let normalized_4 = bpm_list . normalize_beat ( 120.0 , beat! ( 4 ));
assert_eq! ( normalized_4 , beat! ( 4 )); // same time, same beat at 120 BPM
let normalized_8 = bpm_list . normalize_beat ( 120.0 , beat! ( 8 ));
assert_eq! ( normalized_8 , beat! ( 6 )); // beat 8 at variable BPM = beat 6 at constant 120 BPM
// Normalize to 60 BPM timeline
let normalized = bpm_list . normalize_beat ( 60.0 , beat! ( 4 ));
assert_eq! ( normalized , beat! ( 2 )); // beat 4 at 120 BPM = beat 2 at 60 BPM
How BPM Calculation Works
The BpmList automatically computes timestamps when created or modified:
// Example: 120 BPM -> 240 BPM at beat 4
BpmList :: new ( vec! [
BpmPoint { beat : 0 , bpm : 120.0 }, // time: 0.0s
BpmPoint { beat : 4 , bpm : 240.0 }, // time: 2.0s (4 beats at 120 BPM)
])
// Calculation for beat 4:
// - Duration from beat 0 to 4: 4 beats
// - BPM during this period: 120
// - Time = (4 beats) * (60 seconds / 120 BPM) = 2.0 seconds
// After beat 4, the chart is at 240 BPM
// Time for beat 5:
// - Start: 2.0s (time at beat 4)
// - Duration: 1 beat at 240 BPM
// - Additional time = (1 beat) * (60s / 240 BPM) = 0.25s
// - Total time = 2.0 + 0.25 = 2.25s
JSON Serialization
Single BPM
Multiple BPM Changes
[
{
"beat" : [ 0 , 0 , 1 ],
"bpm" : 120.0
}
]
Note: The time field is computed automatically and is not included in JSON.
Common Patterns
Gradual Tempo Changes
Sync with Music
Finding BPM at Beat
use phichain_chart :: bpm_list :: { BpmList , BpmPoint };
use phichain_chart :: beat :: Beat ;
// Gradually speed up
let mut points = vec! [];
for i in 0 .. 8 {
let beat = Beat :: from ( i as f32 * 4.0 );
let bpm = 120.0 + ( i as f32 * 15.0 ); // 120, 135, 150, ...
points . push ( BpmPoint :: new ( beat , bpm ));
}
let bpm_list = BpmList :: new ( points );
Use beat_at_f32 instead of beat_at in performance-critical loops to avoid Beat allocation
The compute() method is called automatically when inserting points, so BPM lists are always ready to use
Time calculations use linear search from the beginning, which is O(n) where n is the number of BPM points
For charts with many BPM changes, consider caching conversion results
Notes
All BPM values should be positive
The first BPM point should typically be at Beat::ZERO
Points are automatically sorted by beat when inserted
Times are recomputed whenever the BPM list is modified
BPM changes are instantaneous at the specified beat