The Android FFT Visualizer is designed with a modular architecture that separates concerns into distinct layers: UI, Data Processing, Audio Capture, and Native Integration.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β UI Layer β
β ββββββββββββββββββ ββββββββββββββββββββββββββββββββββββ β
β β MainActivity β β PerformanceChartActivity β β
β β β β β β
β β - Grid Layout β β - Speed Chart β β
β β - Controls β β - Accuracy Chart β β
β β - 3x FFT Viz β β - Divergence Chart β β
β ββββββββββ¬ββββββββ ββββββββββββββββ¬ββββββββββββββββββββ β
βββββββββββββΌβββββββββββββββββββββββββββΌβββββββββββββββββββββββ
β β
βββββββββββββΌβββββββββββββββββββββββββββΌβββββββββββββββββββββββ
β Presentation Layer β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββββββ β
β β WaveformView β βFrequencyView β β FPSTracker β β
β β β β β β β β
β β - Canvas β β - Canvas β β - Frame timing β β
β β - Time domainβ β - Freq domainβ β - FPS calc β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
βββββββββββββΌβββββββββββββββββββββββββββΌβββββββββββββββββββββββ
β Business Logic Layer β
β βββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ β
β β AudioCaptureManager β β FFT Implementations β β
β β β β ββββββββββ ββββββββββ β β
β β - AudioRecord β β βJavaFFT β βNativeFFTβ β β
β β - Buffer mgmt β β β(Kotlin)β β(C++ JNI)β β β
β β - Normalization β β ββββββββββ ββββββββββ β β
β ββββββββββββ¬βββββββββββ βββββββββββββββββ¬βββββββββββββββ β
βββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββ
β β
βββββββββββββββΌβββββββββββββββββββββββββββββββΌβββββββββββββββββ
β Data Layer β
β βββββββββββββββββββ βββββββββββββββββββ ββββββββββββββ β
β β MetricsCollectorβ β FFTMetrics β β FFTUtils β β
β β β β β β β β
β β - Time series β β - Data class β β - Window β β
β β - Aggregation β β - Timestamp β β - Freq det β β
β β - Storage β β - Latency β β - Diverg β β
β ββββββββββ¬βββββββββ βββββββββββββββββββ ββββββββββββββ β
βββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββ
β Persistence Layer β
β βββββββββββββββββββ β
β β CSVExporter β β
β β β β
β β - Write CSV β β
β β - File mgmt β β
β βββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββ
β Native Layer (JNI) β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β fft_jni.cpp β β
β β - JNI bridge β β
β β - Array conversion β β
β β - Calls ../../cpp/fft_impl.cpp β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Purpose: Main entry point, handles user interactions and orchestrates FFT processing
- Responsibilities:
- Manage audio capture lifecycle (start/stop)
- Display 3-column grid with FFT visualizations
- Handle permissions
- Route to performance charts
- Trigger CSV export
- Key Methods:
startCapture(): Initializes audio recordingstopCapture(): Stops audio recordingprocessAudioData(): Routes audio to FFT implementationsupdateVisualization(): Updates UI with FFT results
- Purpose: Display historical performance metrics
- Responsibilities:
- Render speed, accuracy, and divergence charts
- Handle chart interactions (zoom, pan)
- Load data from MetricsCollector
- Libraries Used: MPAndroidChart
- Purpose: Custom view for time-domain visualization
- Features:
- Canvas-based rendering
- Normalized waveform display
- Grid lines for reference
- Auto-scaling
- Performance: Optimized for 60 FPS rendering
- Purpose: Custom view for frequency-domain visualization
- Features:
- Bar chart representation
- Logarithmic scale option (dB)
- Color-coded magnitude
- Nyquist frequency handling
- Performance: Efficient bar rendering
- Purpose: Manages microphone audio capture
- Technology: Android AudioRecord API
- Configuration:
- Sample Rate: 44,100 Hz
- Format: PCM 16-bit
- Channel: Mono
- Buffer: 4x minimum size
- Flow:
- Initialize AudioRecord
- Start recording on background thread (Coroutine)
- Read audio data in chunks
- Invoke callback with audio buffer
- Continue until stopped
- Algorithm: Cooley-Tukey FFT
- Implementation: Pure Kotlin/Java
- Complexity: O(N log N)
- Features:
- Power-of-2 padding
- Recursive divide-and-conquer
- Complex number arithmetic
- Performance: ~2-3ms for 2048 samples
- Algorithm: Cooley-Tukey FFT
- Implementation: C++11 with STL
- JNI Bridge:
fft_jni.cpp - Features:
- Optimized native code
- Direct memory access
- Standard library only
- Performance: ~1ms for 2048 samples
- Current: Uses JavaFFT as placeholder
- Future: Could integrate via Chaquopy or custom CPython embedding
- Reason for Fallback: Python JNI integration is complex and adds significant overhead
- Type: Data class
- Fields:
implementation: String (C++, Java, Python)timestamp: Long (milliseconds)processingTimeMs: Doublefps: FloatdetectedFrequency: DoublepeakMagnitude: DoubledivergenceFromReference: Double
- Purpose: Collect and aggregate metrics over time
- Features:
- Thread-safe collection
- Limited history (last 1000 entries)
- Per-implementation filtering
- Statistical aggregation (average, etc.)
- Purpose: Utility functions for FFT analysis
- Functions:
findDominantFrequency(): Peak detectioncalculateRMS(): Signal strengthcalculateDivergence(): MSE between implementationscomputeMagnitudes(): Complex to magnitude conversionapplyHammingWindow(): Windowing function
- Purpose: Export metrics to CSV files
- Library: OpenCSV
- Output Location: App-specific external storage
- Format:
Timestamp,Implementation,Processing Time (ms),FPS,Detected Frequency (Hz),Peak Magnitude,Divergence - Features:
- Timestamped filenames
- No special permissions required (Android 14+)
- Compatible with Excel and data analysis tools
- Purpose: JNI bridge between Kotlin and C++
- Functions:
Java_com_flaccidfacade_fftvisualizer_fft_NativeFFT_computeFFT
- Process:
- Receive Java double array
- Convert to C++ std::vector<std::complex>
- Call FFT from repository's cpp/fft_impl.cpp
- Convert result back to Java double array (interleaved real/imag)
- Return to Kotlin
- Purpose: CMake build configuration
- Dependencies:
- Repository's C++ FFT implementation
- Android NDK libraries (log)
- Build Flags: -O3 optimization, C++11 standard
Microphone
β
AudioRecord (44.1kHz, 16-bit PCM)
β
AudioCaptureManager (buffer: 8192 samples)
β
Normalization (Short β Double, [-1, 1])
β
Hamming Window (reduce spectral leakage)
β
ββββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ
β JavaFFT β NativeFFT β PythonFFT β
β (Kotlin) β (C++ JNI) β (Java FB) β
ββββββββ¬ββββββββ΄βββββββ¬ββββββββ΄βββββββ¬ββββββββ
β β β
Magnitude Magnitude Magnitude
Calculation Calculation Calculation
β β β
ββββββββββββββββΌβββββββββββββββ€
β β β
Find Dominant Frequency (peak detection)
β β β
Record Metrics (latency, FPS, freq)
β β β
Update Visualization (waveform + frequency)
β β β
Display in Grid Cell (with overlays)
FFT Processing
β
Create FFTMetrics object
β
MetricsCollector.addMetrics()
β
Store in time-series buffer (max 1000)
β
Available for:
βββ Performance Charts (live update)
βββ CSV Export (batch write)
- UI rendering
- User interactions
- View updates (WaveformView, FrequencyView)
- Audio capture (Dispatchers.IO)
- FFT processing (Dispatchers.Default)
- Metrics collection (Dispatchers.Default)
- CSV export (Dispatchers.IO)
- C++ FFT computation (called from Kotlin coroutine)
-
Efficient Rendering
- Custom views use Canvas (hardware-accelerated)
- Minimize allocations in onDraw()
- Only redraw when data changes
-
Native Code
- C++ FFT compiled with -O3
- Direct memory access
- Minimal JNI overhead
-
Coroutines
- Non-blocking audio processing
- Parallel FFT computation possible
- Structured concurrency
-
Memory Management
- Reuse audio buffers
- Limited metrics history
- Efficient array operations
| Implementation | Processing Time | FPS | Memory |
|---|---|---|---|
| C++ (Native) | ~1.0 ms | 60 FPS | Low |
| Java (Kotlin) | ~2.5 ms | 60 FPS | Medium |
| Python (FB) | ~2.5 ms | 60 FPS | Medium |
-
Permissions
- RECORD_AUDIO: Required, runtime permission
- WRITE_EXTERNAL_STORAGE: Not required (app-specific storage)
-
Data Privacy
- Audio data processed in-memory only
- No network transmission
- CSV exports stored locally
- No cloud backup by default
-
Input Validation
- Audio buffer size checks
- FFT input validation
- Safe array indexing
- FFT correctness (compare against known values)
- Frequency detection accuracy
- Divergence calculation
- Metrics aggregation
- Audio capture β FFT pipeline
- Metrics collection β CSV export
- UI updates from background threads
- Permission flow
- Start/stop capture
- Navigation to charts
- Export functionality
- Real device testing on Samsung devices
- Tone generator validation
- Performance profiling
- Memory leak detection
-
Additional FFT Implementations
- Python (via Chaquopy)
- Go (via gomobile)
- Rust (via JNI)
-
Advanced Visualizations
- Spectrogram (waterfall view)
- 3D frequency plot
- Phase information
-
Real-time Analysis
- Note detection (musical)
- Pitch tracking
- Harmonic analysis
-
Performance Improvements
- GPU-accelerated FFT (RenderScript/Vulkan)
- Multi-threaded processing
- SIMD optimizations
-
User Features
- Adjustable FFT size
- Frequency range zoom
- Audio file analysis
- Benchmark mode