fix: dynamic frequency labels and fix frequency clamping crash
- Frequency tick/label intervals now adapt to zoom level instead of always showing 0–Nyquist (5Hz → 10kHz depending on zoom) - Labels use coarser spacing than ticks to avoid clutter - Fix segfault when zooming out past signal bounds by properly clamping freqViewStart/freqViewEnd to [0,1] with correct width preservation in zoom, pan, and scrollbar drag - Fix firstTick calculation that was off-by-one
This commit is contained in:
+62
-20
@@ -1123,27 +1123,50 @@ static void DrawLabels(Rectangle bounds)
|
||||
DrawTextScaled(label, x, bounds.y + bounds.height + 5, baseFontSize, textColor);
|
||||
}
|
||||
|
||||
// Frequency labels at 1kHz intervals with 200Hz ticks
|
||||
// Frequency labels adapted to current zoom level
|
||||
float maxFreq = (float)app.signal.sampleRate / 2.0f;
|
||||
int maxKhz = (int)(maxFreq / 1000.0f);
|
||||
float freqMin = app.freqViewStart * maxFreq;
|
||||
float freqMax = app.freqViewEnd * maxFreq;
|
||||
|
||||
for (int hz = 0; hz <= maxFreq; hz += 200) {
|
||||
float t = hz / maxFreq;
|
||||
// Choose tick spacing based on zoom range
|
||||
float freqRange = freqMax - freqMin;
|
||||
int tickSpacing;
|
||||
if (freqRange < 20) tickSpacing = 5;
|
||||
else if (freqRange < 50) tickSpacing = 10;
|
||||
else if (freqRange < 200) tickSpacing = 50;
|
||||
else if (freqRange < 1000) tickSpacing = 100;
|
||||
else if (freqRange < 5000) tickSpacing = 200;
|
||||
else if (freqRange < 20000) tickSpacing = 1000;
|
||||
else if (freqRange < 50000) tickSpacing = 5000;
|
||||
else tickSpacing = 10000;
|
||||
|
||||
// Labels use next coarser spacing so they stay readable
|
||||
int labelSpacing = tickSpacing;
|
||||
if (labelSpacing <= 10) labelSpacing = 10;
|
||||
else if (labelSpacing <= 50) labelSpacing = 50;
|
||||
else if (labelSpacing <= 200) labelSpacing = 200;
|
||||
else if (labelSpacing <= 1000) labelSpacing = 1000;
|
||||
else if (labelSpacing <= 5000) labelSpacing = 5000;
|
||||
else labelSpacing = 10000;
|
||||
|
||||
// Round freqMin up to nearest tick spacing (smallest multiple >= freqMin)
|
||||
int firstTick = ((int)(freqMin / tickSpacing)) * tickSpacing;
|
||||
if (firstTick < freqMin) firstTick += tickSpacing;
|
||||
for (int hz = firstTick; hz <= freqMax; hz += tickSpacing) {
|
||||
float t = (hz - freqMin) / freqRange;
|
||||
float y = bounds.y + bounds.height - t * bounds.height;
|
||||
Color tickColor = (hz % 1000 == 0) ? GRAY : Fade(GRAY, 0.4f);
|
||||
DrawLineV((Vector2){ bounds.x - 5, y }, (Vector2){ bounds.x, y }, tickColor);
|
||||
}
|
||||
|
||||
for (int khz = 0; khz <= maxKhz; khz++) {
|
||||
float freq = khz * 1000.0f;
|
||||
if (freq > maxFreq) break;
|
||||
float t = freq / maxFreq;
|
||||
// Draw labels at the coarser spacing
|
||||
for (int hz = firstTick; hz <= freqMax; hz += labelSpacing) {
|
||||
float t = (hz - freqMin) / freqRange;
|
||||
float y = bounds.y + bounds.height - t * bounds.height;
|
||||
char label[32];
|
||||
if (khz == 0) sprintf(label, "0");
|
||||
else if (khz < 10) sprintf(label, "%dk", khz);
|
||||
else sprintf(label, "%d", khz);
|
||||
DrawTextScaled(label, bounds.x - 15, y - 5, baseFontSize, textColor);
|
||||
if (hz < 10000) sprintf(label, "%.0fHz", (float)hz);
|
||||
else sprintf(label, "%.0fkHz", (float)hz / 1000.0f);
|
||||
DrawTextScaled(label, bounds.x - 70, y - 5, baseFontSize, textColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1693,14 +1716,14 @@ int main(int argc, char* argv[])
|
||||
mouseF = app.freqViewStart + mouseF * (app.freqViewEnd - app.freqViewStart);
|
||||
float freqWidth = app.freqViewEnd - app.freqViewStart;
|
||||
float newFreqWidth = freqWidth * zoomFactor;
|
||||
if (newFreqWidth < 0.02f) newFreqWidth = 0.02f;
|
||||
if (newFreqWidth > 1.0f) newFreqWidth = 1.0f;
|
||||
if (newFreqWidth < 0.001f) newFreqWidth = 0.001f;
|
||||
float belowMouse = mouseF - app.freqViewStart;
|
||||
float aboveMouse = app.freqViewEnd - mouseF;
|
||||
app.freqViewStart = mouseF - belowMouse * (newFreqWidth / freqWidth);
|
||||
app.freqViewEnd = mouseF + aboveMouse * (newFreqWidth / freqWidth);
|
||||
if (app.freqViewStart < 0) { app.freqViewStart = 0; app.freqViewEnd = newFreqWidth; }
|
||||
if (app.freqViewEnd > 1) { app.freqViewEnd = 1; app.freqViewStart = 1 - newFreqWidth; }
|
||||
// Clamp to physical frequency limits [0, 1] — can't see beyond Nyquist or below 0 Hz
|
||||
if (app.freqViewStart < 0) { app.freqViewStart = 0; app.freqViewEnd = fminf(app.freqViewEnd, 1.0f); }
|
||||
if (app.freqViewEnd > 1) { app.freqViewEnd = 1; app.freqViewStart = fmaxf(app.freqViewStart, 0.0f); }
|
||||
|
||||
// Invalidate texture cache
|
||||
app.visibleTextureValid = false;
|
||||
@@ -1728,8 +1751,19 @@ int main(int argc, char* argv[])
|
||||
if (app.viewEnd > 1) { app.viewEnd = 1; app.viewStart = 1 - viewWidth; }
|
||||
app.freqViewStart = app.panStartFreqViewStart + dy * freqWidth;
|
||||
app.freqViewEnd = app.panStartFreqViewEnd + dy * freqWidth;
|
||||
if (app.freqViewStart < 0) { app.freqViewStart = 0; app.freqViewEnd = freqWidth; }
|
||||
if (app.freqViewEnd > 1) { app.freqViewEnd = 1; app.freqViewStart = 1 - freqWidth; }
|
||||
// Clamp to physical limits [0, 1]
|
||||
if (app.freqViewStart < 0) {
|
||||
float actualWidth = app.freqViewEnd - app.freqViewStart;
|
||||
app.freqViewStart = 0;
|
||||
app.freqViewEnd = fminf(actualWidth, 1.0f);
|
||||
}
|
||||
if (app.freqViewEnd > 1) {
|
||||
float actualWidth = app.freqViewEnd - app.freqViewStart;
|
||||
app.freqViewEnd = 1;
|
||||
app.freqViewStart = fmaxf(1.0f - actualWidth, 0.0f);
|
||||
}
|
||||
if (app.freqViewStart < 0) app.freqViewStart = 0;
|
||||
if (app.freqViewEnd > 1) app.freqViewEnd = 1;
|
||||
app.visibleTextureValid = false;
|
||||
}
|
||||
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) app.isPanning = false;
|
||||
@@ -2182,8 +2216,16 @@ int main(int argc, char* argv[])
|
||||
float freqWidth = app.freqViewEnd - app.freqViewStart;
|
||||
app.freqViewStart = dragStartFreqViewStart - dy;
|
||||
app.freqViewEnd = app.freqViewStart + freqWidth;
|
||||
if (app.freqViewStart < 0) { app.freqViewStart = 0; app.freqViewEnd = freqWidth; }
|
||||
if (app.freqViewEnd > 1) { app.freqViewEnd = 1; app.freqViewStart = 1 - freqWidth; }
|
||||
if (app.freqViewStart < 0) {
|
||||
app.freqViewStart = 0;
|
||||
app.freqViewEnd = fminf(freqWidth, 1.0f);
|
||||
}
|
||||
if (app.freqViewEnd > 1) {
|
||||
app.freqViewEnd = 1;
|
||||
app.freqViewStart = fmaxf(1.0f - freqWidth, 0.0f);
|
||||
}
|
||||
if (app.freqViewStart < 0) app.freqViewStart = 0;
|
||||
if (app.freqViewEnd > 1) app.freqViewEnd = 1;
|
||||
app.visibleTextureValid = false;
|
||||
}
|
||||
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) { draggingH = false; draggingV = false; }
|
||||
|
||||
Reference in New Issue
Block a user