Complete developer and user documentation for the Pulse Editor feature in SonicSyncSail. This page describes UI behavior, data flow, implementation notes, integration with playback components and known limitations.
The Pulse Editor enables users to select, annotate and save short timestamped audio segments ("pulses") inside songs. These pulses are associated with emotion tags and intensity levels and can be mixed later by the PulseSync mixer to produce a continuous, emotionally curated playback experience.
Primary goals:
Displays current song metadata: album art, title and duration. Also includes:
Primary editing canvas where users define start and end timestamps and preview playback in a loop. Two selection methods are available: Slider view (default) and Waveform view (advanced, with auto intensity detection).
Emotion category chips, derived emotion tags, and an emotion intensity control (Low / Medium / High). The section contains these primary controls:
Lists saved segments for the loaded song. Features:
Uses Material3 double-handle slider. Behavior notes:
Generates a downsampled PCM waveform for the loaded MP3 file and overlays draggable handles. Behavior notes:
Common controls present below both Slider and Waveform modes:
>> << <-- --> >> << (representing incremental single-second shifts of left / right handles and entire selection).Looping behavior: The preview loop always restarts at the start timestamp. Adjusting timestamps while the preview is playing causes the playhead to reposition to the new start time and continue looping (until pause).
Structure and validation:
Why intensity matters: Intensity provides a compact representation of pulse energy (bpm proxy, loudness and transient activity). The PulseMixer uses intensity to prefer smoother transitions between segments by selecting pulses with matching intensity for consecutive mixes.
Button state rules:
Save Segment is disabled until the editor detects at least one change in timestamps or settings.Update Segment and follows the same enablement rules.Primary storage is a Room database table that holds metadata for each pulse segment. The app also mirrors essential metadata inside MediaStore / local caches for fast lookup.
@Entity(tableName = "pulse_segments")
data class PulseSegment(
@PrimaryKey val id: String,
val trackId: String, // id that links to MediaStore / app track entity
val startMs: Long,
val endMs: Long,
val category: String,
val tag: String,
val intensity: String, // "low" | "medium" | "high"
val createdAt: Long,
val updatedAt: Long
)
When the user saves a segment:
The preview player and PulseMixer rely on Media3 (ExoPlayer) with ClippingMediaSource to play exact timestamped regions.
startMs and ends at endMs.startMs to loop without gaps.When Sync Mode is active, the mixer builds a playlist of clipped sources (one per saved pulse). Between clips the mixer applies:
Waveform generation is explicitly supported for MP3 files only. Implementation notes:
Important: Waveform generation does not run for non-MP3 formats — gracefully fall back to the slider view and surface a message explaining the limitation to users.
Waveform generation and DSP analyses must run on a worker thread (Coroutines + Dispatchers.Default). UI updates should be dispatched to the Main thread.
// Pseudocode
val mediaItem = MediaItem.fromUri(trackUri)
val player = ExoPlayer.Builder(context).build()
val dataSourceFactory = DefaultDataSource.Factory(context)
val mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(mediaItem)
val clipped = ClippingMediaSource(mediaSource, startMs * 1000, endMs * 1000)
player.setMediaSource(clipped)
player.prepare()
player.play()
When updating an existing segment, keep a lightweight undo buffer so users can revert accidental changes (optional enhancement).
trackId to quickly fetch pulses for a given track.category if category-based retrieval becomes frequent.Documentation generated for Dhana — review and request adjustments. Once approved I will align styles precisely to the Tag Editor page and can provide example component code for the editor UI.