// This file is part of the 64k demo project. // It implements the specview tool for visualizing spectrograms. // Renders spectral data as ASCII art in the console. #include // For std::max_element #include #include #include #include // 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 \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 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; }