diff options
| author | skal <pascal.massimino@gmail.com> | 2026-01-27 23:09:27 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-01-27 23:10:49 +0100 |
| commit | 9dcf94ab01269311b4e5d39be23c95560904c626 (patch) | |
| tree | ac271af3d51d7ee1bce6827f81e97f1f463336db /tools/specview.cc | |
| parent | 364d9e60e3c27cb131a598fe5f83deb74493319f (diff) | |
feat: Implement spectool & specview; refactor coding style; update docs
This commit introduces new tools for spectrogram manipulation and visualization, establishes a consistent coding style, and updates project documentation.
Key changes include:
- **Spectrogram Tools:
- : A command-line utility for analyzing WAV/MP3 files into custom spectrogram format and playing back these spectrograms via the synth engine.
- : A command-line tool for visualizing spectrogram files as ASCII art in the console.
- **Coding Style Enforcement:
- Added a configuration file enforcing LLVM-based style with 2-space indentation, no tabs, and an 80-column line limit.
- Renamed all C++ source files from to for project consistency.
- Applied automatic formatting using
exit across the entire codebase.
- **Documentation & Workflow:
- Created to define a commit policy requiring tests to pass before committing.
- Updated with instructions for building and using and , and referenced .
- Updated and to reflect the new tools, audio architecture decisions (real-time additive synthesis, double-buffering for dynamic updates, WAV/MP3 support), coding style, and development workflow.
- **Build System:
- Modified to:
- Include new targets for and under the option.
- Update source file extensions to .
- Add a new end-to-end test for to the suite.
Diffstat (limited to 'tools/specview.cc')
| -rw-r--r-- | tools/specview.cc | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/tools/specview.cc b/tools/specview.cc new file mode 100644 index 0000000..77b362c --- /dev/null +++ b/tools/specview.cc @@ -0,0 +1,94 @@ +#include <stdio.h> +#include <string.h> +#include <vector> +#include <algorithm> // For std::max_element + +// Redefine SpecHeader from spectool.cc +struct SpecHeader { + char magic[4]; + int32_t version; + int32_t dct_size; + int32_t num_frames; +}; + +void print_usage() { + printf("Usage: specview <input.spec>\n"); + printf("Displays an ASCII representation of a spectrogram file.\n"); +} + +int main(int argc, char** argv) { + if (argc < 2) { + print_usage(); + return 1; + } + + const char* input_path = argv[1]; + + FILE* f_in = fopen(input_path, "rb"); + if (!f_in) { + printf("Error: Failed to open input file: %s\n", input_path); + return 1; + } + + SpecHeader header; + if (fread(&header, sizeof(SpecHeader), 1, f_in) != 1 || strncmp(header.magic, "SPEC", 4) != 0) { + printf("Error: Invalid spectrogram file format.\n"); + fclose(f_in); + return 1; + } + + if (header.version != 1) { + printf("Error: Unsupported spectrogram version %d.\n", header.version); + fclose(f_in); + return 1; + } + + std::vector<float> spec_data(header.num_frames * header.dct_size); + if (fread(spec_data.data(), sizeof(float), spec_data.size(), f_in) != spec_data.size()) { + printf("Error: Failed to read all spectrogram data.\n"); + fclose(f_in); + return 1; + } + fclose(f_in); + + printf("Spectrogram: %s\n", input_path); + printf(" DCT Size: %d\n", header.dct_size); + printf(" Num Frames: %d\n", header.num_frames); + + // Find max magnitude for normalization + float max_mag = 0.0f; + for (float val : spec_data) { + max_mag = std::max(max_mag, fabsf(val)); + } + if (max_mag == 0.0f) max_mag = 1.0f; // Avoid division by zero + + // ASCII visualization + const char* gradient = " .:-=+*#%@"; + int gradient_len = strlen(gradient); + + printf("\nASCII Visualization:\n"); + for (int frame = 0; frame < header.num_frames; ++frame) { + printf("%4d: ", frame); + const float* current_frame_data = spec_data.data() + frame * header.dct_size; + + // Average bins into fewer columns for better fit on console + const int display_cols = 80; // Max console width + const int bins_per_col = header.dct_size / display_cols; // Divide into 80 bins + + for (int col = 0; col < display_cols; ++col) { + float sum_mag = 0.0f; + for (int bin_idx = 0; bin_idx < bins_per_col; ++bin_idx) { + int current_bin = col * bins_per_col + bin_idx; + if (current_bin < header.dct_size) { + sum_mag += fabsf(current_frame_data[current_bin]); + } + } + float avg_mag = sum_mag / bins_per_col; + int char_idx = (int)((avg_mag / max_mag) * (gradient_len - 1)); + printf("%c", gradient[char_idx]); + } + printf("\n"); + } + + return 0; +} |
