diff --git a/src/spectrogram.c b/src/spectrogram.c index 824cd90..e731a19 100644 --- a/src/spectrogram.c +++ b/src/spectrogram.c @@ -102,6 +102,10 @@ typedef struct { bool loaded; bool stftComputed; + // Playback state + float playheadT; // 0-1 normalized position in selection + float playheadElapsed; // Elapsed seconds since play started + // Time selection (0-1 normalized) float timeSelectionStart; float timeSelectionEnd; @@ -1238,6 +1242,28 @@ static void DrawSelectionDrag(Rectangle bounds) DrawRectangleLinesEx((Rectangle){ x, y, w, h }, 2, YELLOW); } +// ============================================================================ +// Playhead +// ============================================================================ + +static void DrawPlayhead(Rectangle bounds) +{ + if (!app.isPlaying || app.playheadT < 0.0f || app.playheadT > 1.0f) return; + + float timePos = app.timeSelectionStart + app.playheadT * (app.timeSelectionEnd - app.timeSelectionStart); + float viewWidth = app.viewEnd - app.viewStart; + float t = (timePos - app.viewStart) / viewWidth; + float x = bounds.x + t * bounds.width; + + // Clamp to bounds + x = fmaxf(bounds.x, fminf(bounds.x + bounds.width, x)); + + // Draw vertical line + DrawLine(x, bounds.y, x, bounds.y + bounds.height, RED); + // Draw semi-transparent overlay to make it stand out + DrawRectangle(x - 2, bounds.y, 4, bounds.height, (Color){ 255, 0, 0, 60 }); +} + // ============================================================================ // PNG Export // ============================================================================ @@ -1416,6 +1442,8 @@ static void DrawSidebar(void) if (app.isPlaying && AudioPlaybackSound.frameCount > 0) { StopSound(AudioPlaybackSound); app.isPlaying = false; + app.playheadElapsed = 0; + app.playheadT = 0; } else { PlaySelectedRegion(); app.isPlaying = true; @@ -1665,6 +1693,12 @@ int main(int argc, char* argv[]) app.isPlaying = false; app.playbackFinished = true; } + // Track playhead position manually + app.playheadElapsed += GetFrameTime(); + float selectionDuration = (app.timeSelectionEnd - app.timeSelectionStart) * app.signal.duration; + if (selectionDuration > 0) { + app.playheadT = app.playheadElapsed / selectionDuration; + } } // Handle window resize @@ -1828,6 +1862,8 @@ int main(int argc, char* argv[]) StopSound(AudioPlaybackSound); app.isPlaying = false; app.playbackFinished = false; + app.playheadElapsed = 0; + app.playheadT = 0; } else if (app.playbackFinished) { // Playback finished naturally - restart from beginning PlaySelectedRegion(); @@ -2233,6 +2269,7 @@ int main(int argc, char* argv[]) if (app.showGrid) DrawSpectrogramGrid(viewBounds, 10, 8, Fade(GRAY, 0.3f)); DrawSelection(viewBounds); DrawSelectionDrag(viewBounds); + DrawPlayhead(viewBounds); DrawLabels(viewBounds); float maxFreq = (float)app.signal.sampleRate / 2.0f; float freqMin = app.freqViewStart * maxFreq;