// spectrogram_types.h - Shared types, constants, globals, and small math helpers. // This is the "spine" header included by every module. #ifndef SPECTROGRAM_TYPES_H #define SPECTROGRAM_TYPES_H #include "raylib.h" #include "utils.h" // AudioSignal, SignalStats #include "primitives.h" // ScopeView, WaveformData #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef CYAN #define CYAN (Color){ 0, 255, 255, 255 } #endif // ============================================================================ // Configuration // ============================================================================ #define FFT_SIZE_DEFAULT 2048 #define FFT_SIZE_MAX 2048 #define FFT_SIZE_MIN 128 #define HOP_RATIO 4 // FFT_SIZE / HOP_SIZE = 4 means 75% overlap #define MAX_SAMPLE_RATE 48000 #define LOUDNESS_FLOOR_DB -80.0f // Base resolution for proportional UI scaling (see GetUIScale in render.c) #define BASE_WIDTH 1280 #define BASE_HEIGHT 800 #define FFT_CACHE_SIZE 4 // ============================================================================ // Data Structures // ============================================================================ typedef enum { COLORMAP_GRAYS = 0, COLORMAP_INFERNO, COLORMAP_VIRIDIS, COLORMAP_PLASMA, COLORMAP_HOT, COLORMAP_COOL, COLORMAP_COUNT } ColormapType; typedef struct { float frequency; float amplitude; float phase; } FrequencyData; typedef struct { FrequencyData* spectrum; FrequencyData* derivativeSpectrum; // STFT with derivative window (for synchrosqueezing) int numBins; int sampleOffset; int sampleCount; } StftSegment; typedef struct { StftSegment* segments; int numSegments; int sampleRate; int totalSamples; bool useHannWindow; } StftResult; typedef struct { int fftSize; StftResult result; int accessOrder; // lower = more recently accessed } FFTCacheEntry; typedef struct { FFTCacheEntry entries[FFT_CACHE_SIZE]; int count; int nextOrder; } FFTSizeCache; typedef struct { AudioSignal signal; StftResult stft; Image spectrogramImage; Texture2D spectrogramTexture; 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; bool isTimeSelecting; // Frequency selection (0-1 normalized) float freqSelectionStart; float freqSelectionEnd; bool isFreqSelecting; // Export settings float exportScale; char exportDir[4096]; char exportMessage[256]; Vector2 selectStartPos; // For minimum drag distance check bool isDraggingSelection; // Dragging existing selection box Vector2 dragSelectionStartPos; // Mouse position when started dragging selection float dragSelectionTimeStart; // Selection start time when dragging float dragSelectionFreqStart; // Selection freq start when dragging // Viewport/zoom controls float viewStart; // 0-1, start of visible time region float viewEnd; // 0-1, end of visible time region float freqViewStart; // 0-1, start of visible frequency region (0 = 0Hz) float freqViewEnd; // 0-1, end of visible frequency region (1 = Nyquist) bool isPanning; float panStartViewStart; float panStartViewEnd; float panStartFreqViewStart; float panStartFreqViewEnd; Vector2 panStartPos; // Cached visible texture Texture2D visibleTexture; int cachedVisibleStart; int cachedVisibleEnd; int cachedVisibleStartY; int cachedVisibleEndY; bool visibleTextureValid; // Display settings float amplitudeFloorDb; float amplitudeCeilingDb; ColormapType colormap; bool showGrid; int fftSize; // Current FFT size (128-2048) // File browser state bool showFileBrowser; char browserPath[512]; char** browserFiles; bool* browserIsDir; int browserFileCount; int browserScroll; int browserSelected; bool isBrowsing; // Playback state bool isPlaying; bool playbackFinished; // Track if playback completed naturally // Loading/processing state int loadingPhase; // 0 = computing STFT, 1 = generating texture float loadingProgress; // 0.0 to 1.0 overall progress int currentSTFTSegment; // Which segment we're on for incremental processing // Adaptive resolution: skipFactor=1 means compute all segments, skipFactor=N // means compute every Nth segment (faster initial load, overview-only). // highResFinished tracks whether full-res segments have been computed for // the current view range. int skipFactor; bool highResFinished; // Background high-res computation state. // After the overview (skipFactor-strided) loads, missing segments are // filled in at full resolution in the background while the user is idle. int bgHighResSeg; // next segment index to compute at high-res bool bgFinished; // true when all segments are computed at high-res int lastInteractedFrame; // frame counter when last user interaction occurred bool isBgProcessing; // true while background task is actively computing // FFT size cache — LRU cache of previously computed STFT results. // When user switches FFT sizes, we check the cache first to avoid // recomputing. When cache is full, we evict the least-recently-used entry. FFTSizeCache fftCache; // Waveform scope view (underneath spectrogram viewport) ScopeView scopeView; bool showScope; // Toggle to show/hide scope view // Scope view divider float dividerY; // Y position of divider between spectrogram and scope (0-1 normalized) bool isDividing; // True while user is dragging the divider Vector2 dividerStartPos; // Mouse position when started dividing float dividerStartY; // Spectro height when started dividing } SpectrogramApp; // ============================================================================ // Global State (defined in spectrogram.c) // ============================================================================ extern SpectrogramApp app; extern Sound AudioPlaybackSound; extern Texture2D colormapTexture; extern Font mainFont; // ============================================================================ // Small math helpers (header-inline so every module can use them) // ============================================================================ static inline float AmplitudeToDecibels(float amplitude) { if (amplitude < 0.0001f) amplitude = 0.0001f; return 20.0f * log10f(amplitude); } static inline float Clamp(float value, float min, float max) { if (value < min) return min; if (value > max) return max; return value; } #endif // SPECTROGRAM_TYPES_H