diff --git a/src/render.c b/src/render.c index 931689b..245bf75 100644 --- a/src/render.c +++ b/src/render.c @@ -481,6 +481,55 @@ void DrawSelectionDrag(Rectangle bounds) DrawStatPanel(bounds, (Rectangle){ x, y, w, h }); } +// Floating time/frequency/level tag that follows the cursor over the +// spectrogram (suppressed while selecting/panning, which have their own +// readout). The level is the STFT magnitude at that bin, in dB. +void DrawCursorReadout(Rectangle bounds) +{ + if (!app.loaded || !app.stftComputed || app.signal.samples == NULL) return; + if (app.sel.isTimeSelecting || app.sel.isFreqSelecting || app.sel.isDragging || + app.view.isPanning) return; + Vector2 m = GetMousePosition(); + if (!CheckCollisionPointRec(m, bounds)) return; + + float tFrac = app.view.start + ((m.x - bounds.x) / bounds.width) * (app.view.end - app.view.start); + float fFrac = app.view.freqStart + (1.0f - (m.y - bounds.y) / bounds.height) * (app.view.freqEnd - app.view.freqStart); + float timeSec = tFrac * app.signal.duration; + float nyquist = app.signal.sampleRate * 0.5f; + float freqHz = fFrac * nyquist; + + // Sample the STFT level at this (time, freq). + char level[32] = "--"; + if (app.stft.numSegments > 0) { + int seg = (int)(tFrac * app.stft.numSegments); + if (seg < 0) seg = 0; + if (seg >= app.stft.numSegments) seg = app.stft.numSegments - 1; + const StftSegment* s = &app.stft.segments[seg]; + if (s->spectrum && s->numBins > 1) { + float binHz = nyquist / (float)(s->numBins - 1); + int bin = (int)(freqHz / binHz + 0.5f); + if (bin < 0) bin = 0; + if (bin >= s->numBins) bin = s->numBins - 1; + sprintf(level, "%.1f dB", AmplitudeToDecibels(s->spectrum[bin].amplitude)); + } + } + + char text[80]; + sprintf(text, "%.3fs %.0f Hz %s", timeSec, freqHz, level); + int fontSize = 10; + int tw = MeasureText(text, fontSize); + int boxW = tw + 12, boxH = fontSize + 8; + + // Offset up-right of the cursor; flip to keep it inside the viewport. + float bx = m.x + 14, by = m.y - boxH - 6; + if (bx + boxW > bounds.x + bounds.width) bx = m.x - boxW - 14; + if (by < bounds.y) by = m.y + 14; + + DrawRectangle((int)bx, (int)by, boxW, boxH, (Color){ 0, 0, 0, 200 }); + DrawRectangleLines((int)bx, (int)by, boxW, boxH, Fade(SKYBLUE, 0.6f)); + DrawText(text, (int)bx + 6, (int)by + 4, fontSize, (Color){ 180, 220, 255, 255 }); +} + // ============================================================================ // Playhead // ============================================================================ diff --git a/src/render.h b/src/render.h index 2ed7ec2..5874175 100644 --- a/src/render.h +++ b/src/render.h @@ -25,6 +25,7 @@ void DrawSpectrogramGrid(Rectangle bounds, int numCellsX, int numCellsY, Color c void DrawLabels(Rectangle bounds); void DrawSelection(Rectangle bounds); void DrawSelectionDrag(Rectangle bounds); +void DrawCursorReadout(Rectangle bounds); void DrawPlayhead(Rectangle bounds); #endif // RENDER_H diff --git a/src/spectrogram.c b/src/spectrogram.c index 6cbdb83..34ba1b1 100644 --- a/src/spectrogram.c +++ b/src/spectrogram.c @@ -964,6 +964,7 @@ int main(int argc, char* argv[]) DrawSelectionDrag(viewBounds); DrawPlayhead(viewBounds); DrawLabels(viewBounds); + if (!UiModalOpen()) DrawCursorReadout(viewBounds); float maxFreq = (float)app.signal.sampleRate / 2.0f; float freqMin = app.view.freqStart * maxFreq; float freqMax = app.view.freqEnd * maxFreq;