09 BPM
In this chapter, we will display each BPM change as a purple line and value in the right margin.
BPM Change
In play mode, we do not need to implement the BPM change archetype. BPM changes are automatically used by the timing functions, and we do not need to do anything else with them.
In preview, however, we want to show where the BPM changes occur and their new values.
Declaring
In guide/lib/skin.py, map a field to the standard purple grid sprite. Keep the existing fields. This reuses the grid resource from the selected skin:
python
@skin
class Skin:
# ...
bpm_change_line: StandardSprite.GRID_PURPLEBPM Change Archetype
Create guide/preview/bar_line.py. Use StandardArchetypeName to associate the class with standard BPM change entities, and use StandardImport to read their beat and BPM values.
Like a Note, a BPM change can be the last visible event in a level. Its preprocess callback must therefore update both Chart.beats and Chart.duration. Its render callback draws the purple line and prints the BPM value. Use this complete file:
python
from sonolus.script.archetype import (
PreviewArchetype,
StandardArchetypeName,
StandardImport,
)
from sonolus.script.printing import PrintColor, PrintFormat
from sonolus.script.timing import beat_to_time
from guide.lib.skin import Skin
from guide.preview.chart import Chart, draw_line, print_at_time
class PreviewBpmChange(PreviewArchetype):
name = StandardArchetypeName.BPM_CHANGE
beat: StandardImport.BEAT
bpm: StandardImport.BPM
def preprocess(self):
Chart.beats = max(Chart.beats, self.beat)
Chart.duration = max(Chart.duration, beat_to_time(self.beat))
def render(self):
draw_line(Skin.bpm_change_line, self.beat, order=1, a=0.5)
print_at_time(
self.bpm,
beat_to_time(self.beat),
fmt=PrintFormat.BPM,
color=PrintColor.PURPLE,
side="right",
)Then register it in the archetypes list in guide/preview/mode.py:
python
from guide.preview.bar_line import PreviewBpmChange
preview_mode = PreviewMode(
archetypes=[
PreviewInitialization,
PreviewStage,
PreviewNote,
PreviewBpmChange,
],
skin=Skin,
)Order 1 places a BPM marker above the regular beat line at the same beat.
Checkpoint
Refresh Preview. Each BPM change should have a purple line across the lane and a purple BPM value in the right margin. The marker at beat 0 should appear even though the measure 1 and time 0 labels were skipped.