Simplify UI: fixed FFT 128 with synchrosqueezing always on, removed FFT slider and SQ checkbox
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
+3
-51
@@ -27,9 +27,7 @@
|
||||
// Configuration
|
||||
// ============================================================================
|
||||
|
||||
#define FFT_SIZE_DEFAULT 2048
|
||||
#define FFT_SIZE_MAX 2048
|
||||
#define FFT_SIZE_MIN 128
|
||||
#define FFT_SIZE 128
|
||||
#define HOP_RATIO 4 // FFT_SIZE / HOP_SIZE = 4 means 75% overlap
|
||||
#define MAX_SAMPLE_RATE 48000
|
||||
#define LOUDNESS_FLOOR_DB -80.0f
|
||||
@@ -116,8 +114,6 @@ typedef struct {
|
||||
float amplitudeCeilingDb;
|
||||
ColormapType colormap;
|
||||
bool showGrid;
|
||||
int fftSize; // Current FFT size (128-2048)
|
||||
bool useSynchrosqueezing; // Enable synchrosqueezing for sharper display
|
||||
|
||||
// File browser state
|
||||
bool showFileBrowser;
|
||||
@@ -466,7 +462,6 @@ static void GenerateSpectrogramTexture(StftResult* stft, Image* image, Texture2D
|
||||
if (stft->segments[seg].spectrum[bin].amplitude > maxAmplitude)
|
||||
maxAmplitude = stft->segments[seg].spectrum[bin].amplitude;
|
||||
|
||||
if (app.useSynchrosqueezing) {
|
||||
// ===== SYNCHROSQUEEZING =====
|
||||
// Reassign energy to true frequencies using derivative STFT
|
||||
|
||||
@@ -474,7 +469,6 @@ static void GenerateSpectrogramTexture(StftResult* stft, Image* image, Texture2D
|
||||
float* accumBuffer = (float*)calloc(width * height, sizeof(float));
|
||||
|
||||
// Noise threshold: only reassign bins with significant energy
|
||||
// This prevents noise from being reassigned to random frequencies
|
||||
float noiseThreshold = maxAmplitude * 0.01f; // 1% of max amplitude
|
||||
|
||||
for (int seg = 0; seg < width; seg++) {
|
||||
@@ -542,19 +536,6 @@ static void GenerateSpectrogramTexture(StftResult* stft, Image* image, Texture2D
|
||||
}
|
||||
|
||||
free(accumBuffer);
|
||||
} else {
|
||||
// ===== STANDARD STFT (no synchrosqueezing) =====
|
||||
for (int seg = 0; seg < width; seg++) {
|
||||
for (int bin = 0; bin < height; bin++) {
|
||||
float amplitude = stft->segments[seg].spectrum[bin].amplitude;
|
||||
float db = AmplitudeToDecibels(amplitude);
|
||||
float normalized = (db - app.amplitudeFloorDb) / (app.amplitudeCeilingDb - app.amplitudeFloorDb);
|
||||
normalized = Clamp(normalized, 0.0f, 1.0f);
|
||||
int pixelIndex = (height - 1 - bin) * width + seg;
|
||||
pixels[pixelIndex] = GetColormapColor(normalized, app.colormap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (texture->id != 0) UnloadTexture(*texture);
|
||||
*texture = LoadTextureFromImage(*image);
|
||||
@@ -989,23 +970,6 @@ static void DrawSidebar(void)
|
||||
// Title
|
||||
DrawText("Spectrogram Controls", x, y, 14, WHITE); y += 25;
|
||||
|
||||
// FFT Size slider
|
||||
DrawText(TextFormat("FFT Size: %d (%.1f Hz/bin)", app.fftSize, (float)app.signal.sampleRate / app.fftSize), x, y, fontSize, LIGHTGRAY); y += 18;
|
||||
Rectangle fftSlider = { x, y, sidebarWidth - 10, 20 };
|
||||
float fftValue = (float)(app.fftSize - FFT_SIZE_MIN) / (FFT_SIZE_MAX - FFT_SIZE_MIN);
|
||||
DrawSlider(fftSlider, fftValue);
|
||||
if (UpdateSlider(fftSlider, &fftValue)) {
|
||||
int newFFT = FFT_SIZE_MIN + (int)(fftValue * (FFT_SIZE_MAX - FFT_SIZE_MIN));
|
||||
// Round to power of 2
|
||||
while ((newFFT & (newFFT - 1)) != 0) newFFT++;
|
||||
if (newFFT != app.fftSize && newFFT >= FFT_SIZE_MIN && newFFT <= FFT_SIZE_MAX) {
|
||||
app.fftSize = newFFT;
|
||||
app.stftComputed = false;
|
||||
needsRegen = true;
|
||||
}
|
||||
}
|
||||
y += 25;
|
||||
|
||||
// dB Floor slider
|
||||
DrawText(TextFormat("dB Floor: %.1f", app.amplitudeFloorDb), x, y, fontSize, LIGHTGRAY); y += 18;
|
||||
Rectangle dbSlider = { x, y, sidebarWidth - 10, 20 };
|
||||
@@ -1043,16 +1007,6 @@ static void DrawSidebar(void)
|
||||
DrawRectangleLinesEx(gridCheck, 1, WHITE);
|
||||
DrawText("Show Grid", x + 25, y + 2, fontSize, LIGHTGRAY); y += 25;
|
||||
|
||||
// Synchrosqueezing toggle
|
||||
Rectangle sqCheck = { x, y, 18, 18 };
|
||||
if (CheckCollisionPointRec(GetMousePosition(), sqCheck) && IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
|
||||
app.useSynchrosqueezing = !app.useSynchrosqueezing;
|
||||
needsRegen = true;
|
||||
}
|
||||
DrawRectangleRec(sqCheck, app.useSynchrosqueezing ? BLUE : DARKGRAY);
|
||||
DrawRectangleLinesEx(sqCheck, 1, WHITE);
|
||||
DrawText("Synchrosqueezing (sharp)", x + 25, y + 2, fontSize, LIGHTGRAY); y += 25;
|
||||
|
||||
// File loading
|
||||
DrawText("File:", x, y, fontSize, LIGHTGRAY); y += 18;
|
||||
Rectangle fileButton = { x, y, sidebarWidth - 10, 25 };
|
||||
@@ -1111,7 +1065,7 @@ static void DrawSidebar(void)
|
||||
if (app.loaded) {
|
||||
DrawText(TextFormat("Sample Rate: %d Hz", app.signal.sampleRate), x, y, fontSize, GRAY); y += 16;
|
||||
DrawText(TextFormat("Duration: %.2f sec", app.signal.duration), x, y, fontSize, GRAY); y += 16;
|
||||
DrawText(TextFormat("Max Freq: %.1f kHz", (float)app.signal.sampleRate / 2000.0f), x, y, fontSize, GRAY); y += 16;
|
||||
DrawText(TextFormat("FFT: %d, %.1f Hz/bin (synchrosqueezed)", FFT_SIZE, (float)app.signal.sampleRate / FFT_SIZE), x, y, fontSize, GRAY); y += 16;
|
||||
} else {
|
||||
DrawText("No file loaded", x, y, fontSize, GRAY); y += 16;
|
||||
}
|
||||
@@ -1177,10 +1131,8 @@ int main(int argc, char* argv[])
|
||||
app.cachedVisibleStart = -1;
|
||||
app.cachedVisibleEnd = -1;
|
||||
app.visibleTextureValid = false;
|
||||
app.fftSize = FFT_SIZE_DEFAULT;
|
||||
app.isPlaying = false;
|
||||
app.playbackFinished = false;
|
||||
app.useSynchrosqueezing = true; // Enabled by default
|
||||
|
||||
GenerateColormapTexture();
|
||||
ScanDirectory(GetWorkingDirectory());
|
||||
@@ -1396,7 +1348,7 @@ int main(int argc, char* argv[])
|
||||
if (app.loaded && !app.stftComputed) {
|
||||
TraceLog(LOG_INFO, "Computing STFT...");
|
||||
double startTime = GetTime();
|
||||
ComputeSTFT(&app.signal, &app.stft, app.fftSize);
|
||||
ComputeSTFT(&app.signal, &app.stft, FFT_SIZE);
|
||||
TraceLog(LOG_INFO, "STFT computed in %.2f sec (%d segments)", GetTime() - startTime, app.stft.numSegments);
|
||||
GenerateSpectrogramTexture(&app.stft, &app.spectrogramImage, &app.spectrogramTexture);
|
||||
app.stftComputed = true;
|
||||
|
||||
Reference in New Issue
Block a user