# Minimal Audio Tracker in addition to being able to generate spectrograms (aka "Samples") on the fly and play them at once, we need a way to assemble samples (assets or generated) into modifiable patterns and loops. Like what the Trackers were doing in the old time. ## The idea A script can take a 'tracker music' text file that describes the sequence of samples (a 'pattern') in a first part. In a second part, these sequence a laid out with a timestamp (potentially overlapping) to generate the full music score. The patterns' samples (spectrograms) are not yet generated, it's just the 'musical score' here. We still need to 'play' the score but with modifiers applied. ### Modifiers For diversity, these essential patterns can be modified on the fly before being generated as spectrogram on the fly. Modifiers could be: * randomize (for drums, e.g.) * add accents and stresses * modulate volume * add distortion or noise * add 'grain' and static noise * flanger, vocoding, robotic voice, etc. * etc. These modifiers are applied to a predefined pattern just before it's generated for playback (or assembling in the final track). ### How would that work in practice? The musical score is a text file, that a tool will convert to run-time code to be compiled in the final binary demo64k. This generated code can be mixed with fixed code from the demo codebase itself (explosion predefined at a given time ,etc.) The baking is done at compile time, and the code will go in src/generated/ ## .track File Format ### Timing System **Unit-less Timing Convention:** - All time values are **unit-less** (not beats or seconds) - Convention: **1 unit = 4 beats** - Conversion to seconds: `seconds = units * (4 / BPM) * 60` - At 120 BPM: 1 unit = 2 seconds This makes patterns independent of BPM - changing BPM only affects playback speed, not pattern structure. ### File Structure ``` # Comments start with # BPM # Optional, defaults to 120 BPM SAMPLE # Define sample (asset or generated note) PATTERN LENGTH # Define pattern with unit-less duration , , , # Pattern events SCORE # Score section (pattern triggers) , ``` ### Examples #### Simple 4-beat pattern (1 unit): ``` PATTERN kick_snare LENGTH 1.0 0.00, ASSET_KICK_1, 1.0, 0.0 # Start of pattern (beat 0) 0.25, ASSET_SNARE_1, 0.9, 0.0 # 1/4 through (beat 1) 0.50, ASSET_KICK_1, 1.0, 0.0 # 1/2 through (beat 2) 0.75, ASSET_SNARE_1, 0.9, 0.0 # 3/4 through (beat 3) ``` #### Score triggers: ``` SCORE 0.0, kick_snare # Trigger at 0 seconds (120 BPM) 1.0, kick_snare # Trigger at 2 seconds (1 unit = 2s at 120 BPM) 2.0, kick_snare # Trigger at 4 seconds ``` #### Generated note: ``` SAMPLE NOTE_C4 # Automatically generates C4 note (261.63 Hz) PATTERN melody LENGTH 1.0 0.00, NOTE_C4, 0.8, 0.0 0.25, NOTE_E4, 0.7, 0.0 0.50, NOTE_G4, 0.8, 0.0 ``` ### Conversion Reference At 120 BPM (1 unit = 4 beats = 2 seconds): | Units | Beats | Seconds | Description | |-------|-------|---------|-------------| | 0.00 | 0 | 0.0 | Start | | 0.25 | 1 | 0.5 | Quarter | | 0.50 | 2 | 1.0 | Half | | 0.75 | 3 | 1.5 | Three-quarter | | 1.00 | 4 | 2.0 | Full pattern | ### Pattern Length - `LENGTH` parameter is optional, defaults to 1.0 - Can be any value (0.5 for half-length, 2.0 for double-length, etc.) - Events must be within range `[0.0, LENGTH]` Example of half-length pattern: ``` PATTERN short_fill LENGTH 0.5 # 2 beats = 1 second at 120 BPM 0.00, ASSET_HIHAT, 0.7, 0.0 0.50, ASSET_HIHAT, 0.6, 0.0 # 0.50 * 0.5 = 1 beat into the pattern ```