Rhythm
Practice with rhythms and play-alongs
Visualize rhythmic cycles, isolate tracks, loop sections, and build a reliable practice pulse.

Goal
Circular rhythms make repeating structures visible, while play-alongs combine synchronized tracks and harmony for practical rehearsal.
Interface landmarks
- Source distinguishes embedded videos, hosted files, loops, and multitracks.
- Search and tags narrow a large practice library.
- Cards show availability and open the synchronized player.
- Track controls inside a play-along provide mute, solo, balance, and repeat behavior.
Step-by-step workflow
- Choose a circular rhythm or play-along that matches your style and level.
- Set a comfortable tempo and listen through once before playing.
- Mute, solo, or balance tracks to create space for your own part.
- Loop the difficult section, increase tempo gradually, then perform the complete form.
Practice tips
- Keep the subdivision steady before focusing on fills or ornamentation.
- Record one pass and check whether your attacks align with the pulse.
Worked example
Example: learn a four-bar groove
Open a multitrack groove, solo drums and bass, and clap the subdivision. Add your instrument at half speed, loop four bars until attacks are stable, then restore the remaining tracks and play the entire form.
Canonical project documentation
This reference is generated directly from repository Markdown; it is not duplicated fixture copy.
Source: Documentation/CircularRhythm.md
Canonical State Envelope
A newly created integration template uses:
{
"bpm": 120,
"ppq": 960,
"beatsPerBar": 4,
"beatUnit": 4,
"circularTrack": {
"id": "standalone",
"type": "CIRCULAR",
"name": "New Circular Rhythm",
"config": {
"engineType": "sampler"
},
"audioEngine": {
"engineType": "sampler"
},
"rings": []
}
}The web form's initial state is similar but may omit transport fields it can default later. Therefore consumers must apply defaults rather than requiring every optional key.
The only structural requirements enforced by the integration write controller are:
state is an object
state.circularTrack is an object
state.circularTrack.rings is an array
name is non-emptyRing and step details are normalized for selection and playback, but the persistence column remains flexible.
Timing Interpretation
Transport defaults are normalized for selector output:
bpm: clamped to 40..220
ppq: at least 1
beatsPerBar: at least 1
beatUnit: at least 1The persisted state may contain broader or malformed values because it is flexible JSON. Playback clients should consume normalized controller/provider output where available and defensively clamp state imported from elsewhere.
For radial geometry, hit testing, and conceptual PLL synchronization, see [Mobile Circular Rhythm Guide](./mobile/CircularRhythmGuide.md). Those client recommendations do not expand the backend wire contract.
Troubleshooting
The rhythm is not in the public catalog
Verify isPublic, owner identity, and repository visibility. Paid status does not make a rhythm public.
Saving updates somebody else's rhythm
It should not. The web controller computes canSaveCurrent from both paid write access and CircularRhythmVoter::EDIT; otherwise it creates a copy.
Rings disappear in selector output
Non-array ring or step values are discarded by normalization. Inspect state.circularTrack.rings.
The wrong sampler loads
Inspect both audioEngine and config. Existing config overlays the default engine. A missing engine intentionally falls back to the bundled MuldjordKit SFZ.
Tags appear different for two users
Owner tags are shared; user tags are viewer-specific overwrites.
Delete returns 404 rather than 403
The web delete action intentionally hides unauthorized object existence by throwing not found when DELETE is denied.
Source: Documentation/PlayAlong.md
Overview
A PlayAlong is a practice-oriented media aggregate. It can represent:
- an embedded video, especially YouTube;
- one hosted audio file;
- a hosted multitrack session with independent stems;
- linked Harmony context;
- tempo and pitch transformation capabilities;
- user-saved mixer/loop settings.
The aggregate describes what is available. It does not imply that every source supports every transformation. Capability flags, source type, file presence, authorization, and transform-service availability all participate.
Track Model
Each PlayAlongTrack contains:
label
path, mimeType, originalFilename, extension
byteSize, checksum, durationMs
role, instrumentCode, stemType
position
volumeDb, pan
isMuted, isSolo, isPrimary
metadataStem types:
full_mix
drums
bass
harmony
melody
click
otherNormalization:
- position is at least zero;
- volume is clamped to
-60..+12dB; - pan is clamped to
-1..+1; - extension, role, and instrument code are lower-cased;
- tracks are ordered by position, then ID.
Track metadata is flexible. Playback code must use stable fields first and tolerate unknown metadata.
Audio Transform Jobs
Single Transform
POST /api/playalongs/{id}/transform-jobsThe source may be the requested track or the root hosted file. At least one tempo or pitch request is required.
Batch Transform
POST /api/playalongs/{id}/transform-batchThe batch endpoint supports a global tempo ratio/target, global key metadata, and per-track pitch changes.
Important clamps:
tempoRatio: 0.25..4.0
targetTempoBpm: at least 1
pitchShiftSemitones: -24..+24Transforms require:
- visible PlayAlong;
- authenticated user;
- ownership or paid membership according to
canTransformPlayAlong(); hosted_filesource type;- a source path;
- matching capability flag.
The controller persists jobs with:
queuedand a payload identifying:
processor = python_audio_transform
source path and MIME
source track
PlayAlong
tempo request
pitch request
optionsBatch processing runs through PlayAlongAudioTransformService with bounded concurrency. Unchanged tracks can be returned as original without creating a job.
Job Lifecycle
PlayAlongTransformJob status constants cover queued, processing, completed, and failed states. Output includes request parameters, output path/MIME/size, error message, and lifecycle timestamps.
A 202 Accepted single-job response means queued, not completed. Clients must not use an output path until status is completed.
Troubleshooting
Transform returns 422
Check source type, source path, requested change, and the corresponding capability flag.
Transform returns 403
The PlayAlong may be visible but the user lacks ownership/paid transformation rights.
Harmony link is absent from output
The Harmony has its own visibility rule and may be private to another owner.
Multitrack setting cannot save
After normalization, there are no playable tracks. Verify IDs correspond to current PlayAlong tracks.
YouTube looper has no loops
Inspect normalized metadata and saved state. A YouTube video ID alone does not create loop ranges.
Volume or pan changes unexpectedly
Entity setters clamp volume and pan. Saved user mixer state is also normalized against current tracks.
Batch output contains original
That track required neither tempo nor pitch processing. This is a successful skip, not a failed job.
Source: Documentation/mobile/CircularRhythmGuide.md
Synchronized Timing (PLL)
The mobile sequencer uses a Phase-Locked Loop (PLL) approach to ensure the UI and Audio never drift:
- Master Phase: The audio engine (Oboe) maintains a continuous phase value from $0.0$ to $1.0$ for the current bar.
- Needle Interpolation: The playback needle position is calculated as $\theta = (\text{phase} \times 360^\circ) - 90^\circ$.
- Sub-sample Accuracy: By using a float-based phase rather than discrete integer steps, the needle moves with 60fps smoothness regardless of the BPM.
Interaction: Polar Painting
The sequencer supports High-Density Multi-touch Sweeping, allowing users to "paint" rhythm patterns across concentric rings.
- Polar Intersector:
- Radius ($r$): $\sqrt{dx^2 + dy^2}$ identifies the ring index.
- Angle ($\theta$): $((\text{atan2}(dy, dx) \times 180/\pi) + 90 + 360) \pmod{360}$ identifies the step index.
- Tactile Feedback: Every toggled step triggers a
TextHandleMovehaptic tick.
Theoretical North (Top-Anchor Rule)
- Beat 1 Alignment: Step 0 of every ring MUST be anchored at 12 o'clock (0°).
- Haptic Anchor: Trigger a
LongPresshaptic pulse exactly as the needle crosses the 12 o'clock position to provide tactile "Downbeat" confirmation.
Quick troubleshooting
- Tracks drift apart: reload the play-along and verify that every file belongs to the same source version.
- Loop clicks or cuts notes: move boundaries away from sustained attacks and recheck bar length.
- You lose the pulse when a track is muted: keep a metronome, percussion, or bass reference audible.
Before you finish
- Tempo and subdivision remain steady without the full mix.
- Loop boundaries cover complete musical beats or bars.
- The final pass works with all intended tracks restored.
Continue in JolyMusic
Open the related tool and apply this workflow immediately to one simple example.