#include #include #include "waveform.h" #define WITHIN_RMS(low, high, rms) \ ((low >= 0 && low <= rms) || (high < 0 && high >= -rms) || (low < 0 && high > 0 && rms > 0)) //#define OUTPUT_WAVEFORM_PNG //#define WAVEFORM_REFERENCE_MODE #ifdef OUTPUT_WAVEFORM_PNG #include #include #define STB_IMAGE_WRITE_IMPLEMENTATION #include // min/max: #BC615E, #F4EAE0 // rms: #FF928F, #E4CAAF // // min/max: #D93A50, #b22f41 // rms: #f44f7a, #c84064 // extra: #f6ac7f, #F5F4FA, #5b524b // left channel: n == 0, right channel: n == 1. #define COLOR_FOR_PIXEL(n, rms) rms ? \ n == 0 ? nn_htonl(0xe4caaf99) : nn_htonl(0xff928fff) : \ n == 0 ? nn_htonl(0xf4eae099) : nn_htonl(0xbc615eff) // ss: current sample, ns: next sample. #define HIT_WAVE(low, high, ss, ns) \ ((ss <= low && ns > low) || (ss > high && ns <= high) || (ss > low && ns <= high)) static void test_write_bitmap(struct cmc_list_entry *entry, u32 width, u32 height, u32 **rgba) { f64 start = nn_get_tick(); *rgba = al_calloc(width * height, 4); u32 channels = entry->raw.fmt.channel_count; u32 samples_per_column = entry->raw.sample_count / width; s32 wave_min = INT16_MIN; s32 wave_max = INT16_MAX; s32 step = (wave_max * 2 + (height - 1)) / height; //s32 step = (wave_max * 2 + (height / 2)) / height; s16 *steps = al_malloc(sizeof(s16) * (height + 1)); for (s32 i = 0; i <= (s32)height; i++) { steps[i] = (s16)MAX(wave_max - step * i, wave_min); } //steps[height] = wave_min; al_assert(steps[height] == wave_min); s64 rms = 0; s16 min, max; s16 low, high; s16 *data = (s16 *)entry->raw.data; const u32 samples_stride = samples_per_column * channels; for (u32 i = 0; i < width; i++) { u32 f = i * samples_stride; for (u32 n = 0; n < channels; n++) { rms = 0; min = wave_max, max = wave_min; for (u32 m = 0; m <= samples_stride; m += channels) { s16 ss = data[f + m + n]; rms += ss * ss; min = MIN(min, ss); max = MAX(max, ss); } rms /= samples_per_column; rms = sqrt(rms); #ifndef WAVEFORM_REFERENCE_MODE for (u32 j = 0; j < height; j++) { low = steps[j + 1], high = steps[j]; if (low < max && high >= min) { (*rgba)[j * width + i] = COLOR_FOR_PIXEL(n, WITHIN_RMS(low, high, rms)); } } #else for (u32 m = 0; m < samples_stride; m += channels) { s16 ss = data[f + m + n]; s16 ns = data[f + m + n + channels]; for (u32 j = 0; j < height; j++) { low = steps[j + 1], high = steps[j]; if (HIT_WAVE(low, high, ss, ns)) { (*rgba)[j * width + i] = COLOR_FOR_PIXEL(n, WITHIN_RMS(low, high, rms)); } } } #endif } } log_info("generating waveform took: %.2fs.", nn_get_tick() - start); //stbi_write_png("./waveform.png", width, height, 4, *rgba, width * 4); /* struct nn_file file; nn_file_open(&file, &al_str_c("./raw_samples.raw"), NNWT_FILE_CREATE); size_t bytes = entry->raw.sample_count * entry->raw.fmt.channel_count * camu_audio_format_bytes_per_sample(&entry->raw.fmt); nn_file_write(&file, entry->raw.data, bytes); nn_file_close(&file); */ } #endif /* static const char *octant_lut[] = { " ", "๐œบจ", "๐œบซ", "๐Ÿฎ‚", "๐œด€", "โ–˜", "๐œด", "๐œด‚", "๐œดƒ", "๐œด„", "โ–", "๐œด…", "๐œด†", "๐œด‡", "๐œดˆ", "โ–€", "๐œด‰", "๐œดŠ", "๐œด‹", "๐œดŒ", "๐Ÿฏฆ", "๐œด", "๐œดŽ", "๐œด", "๐œด", "๐œด‘", "๐œด’", "๐œด“", "๐œด”", "๐œด•", "๐œด–", "๐œด—", "๐œด˜", "๐œด™", "๐œดš", "๐œด›", "๐œดœ", "๐œด", "๐œดž", "๐œดŸ", "๐Ÿฏง", "๐œด ", "๐œดก", "๐œดข", "๐œดฃ", "๐œดค", "๐œดฅ", "๐œดฆ", "๐œดง", "๐œดจ", "๐œดฉ", "๐œดช", "๐œดซ", "๐œดฌ", "๐œดญ", "๐œดฎ", "๐œดฏ", "๐œดฐ", "๐œดฑ", "๐œดฒ", "๐œดณ", "๐œดด", "๐œดต", "๐Ÿฎ…", "๐œบฃ", "๐œดถ", "๐œดท", "๐œดธ", "๐œดน", "๐œดบ", "๐œดป", "๐œดผ", "๐œดฝ", "๐œดพ", "๐œดฟ", "๐œต€", "๐œต", "๐œต‚", "๐œตƒ", "๐œต„", "โ––", "๐œต…", "๐œต†", "๐œต‡", "๐œตˆ", "โ–Œ", "๐œต‰", "๐œตŠ", "๐œต‹", "๐œตŒ", "โ–ž", "๐œต", "๐œตŽ", "๐œต", "๐œต", "โ–›", "๐œต‘", "๐œต’", "๐œต“", "๐œต”", "๐œต•", "๐œต–", "๐œต—", "๐œต˜", "๐œต™", "๐œตš", "๐œต›", "๐œตœ", "๐œต", "๐œตž", "๐œตŸ", "๐œต ", "๐œตก", "๐œตข", "๐œตฃ", "๐œตค", "๐œตฅ", "๐œตฆ", "๐œตง", "๐œตจ", "๐œตฉ", "๐œตช", "๐œตซ", "๐œตฌ", "๐œตญ", "๐œตฎ", "๐œตฏ", "๐œตฐ", "๐œบ ", "๐œตฑ", "๐œตฒ", "๐œตณ", "๐œตด", "๐œตต", "๐œตถ", "๐œตท", "๐œตธ", "๐œตน", "๐œตบ", "๐œตป", "๐œตผ", "๐œตฝ", "๐œตพ", "๐œตฟ", "๐œถ€", "๐œถ", "๐œถ‚", "๐œถƒ", "๐œถ„", "๐œถ…", "๐œถ†", "๐œถ‡", "๐œถˆ", "๐œถ‰", "๐œถŠ", "๐œถ‹", "๐œถŒ", "๐œถ", "๐œถŽ", "๐œถ", "โ–—", "๐œถ", "๐œถ‘", "๐œถ’", "๐œถ“", "โ–š", "๐œถ”", "๐œถ•", "๐œถ–", "๐œถ—", "โ–", "๐œถ˜", "๐œถ™", "๐œถš", "๐œถ›", "โ–œ", "๐œถœ", "๐œถ", "๐œถž", "๐œถŸ", "๐œถ ", "๐œถก", "๐œถข", "๐œถฃ", "๐œถค", "๐œถฅ", "๐œถฆ", "๐œถง", "๐œถจ", "๐œถฉ", "๐œถช", "๐œถซ", "โ–‚", "๐œถฌ", "๐œถญ", "๐œถฎ", "๐œถฏ", "๐œถฐ", "๐œถฑ", "๐œถฒ", "๐œถณ", "๐œถด", "๐œถต", "๐œถถ", "๐œถท", "๐œถธ", "๐œถน", "๐œถบ", "๐œถป", "๐œถผ", "๐œถฝ", "๐œถพ", "๐œถฟ", "๐œท€", "๐œท", "๐œท‚", "๐œทƒ", "๐œท„", "๐œท…", "๐œท†", "๐œท‡", "๐œทˆ", "๐œท‰", "๐œทŠ", "๐œท‹", "๐œทŒ", "๐œท", "๐œทŽ", "๐œท", "๐œท", "๐œท‘", "๐œท’", "๐œท“", "๐œท”", "๐œท•", "๐œท–", "๐œท—", "๐œท˜", "๐œท™", "๐œทš", "โ–„", "๐œท›", "๐œทœ", "๐œท", "๐œทž", "โ–™", "๐œทŸ", "๐œท ", "๐œทก", "๐œทข", "โ–Ÿ", "๐œทฃ", "โ–†", "๐œทค", "๐œทฅ", "โ–ˆ" }; */ #define RMS_BIT (1 << 8) void cmc_draw_waveform(struct cmc_list_entry *entry, u32 width, u32 height, bool include_rms, char ***buf, u32 **rgba) { (void)include_rms; (void)buf; (void)entry; (void)width; (void)height; (void)rgba; #ifdef OUTPUT_WAVEFORM_PNG test_write_bitmap(entry, width, height, rgba); return; #endif // u32 channels = entry->raw.fmt.channel_count; // u32 samples_per_column = entry->raw.sample_count / (width * 2); // // s32 pixel_height = height * 4; // s32 wave_min = INT16_MIN; // s32 wave_max = INT16_MAX; // s32 step = (wave_max * 2 + (pixel_height - 1)) / pixel_height; // // s16 *steps = al_malloc(sizeof(s16) * (pixel_height + 1)); // for (s32 i = 0; i <= (s32)pixel_height; i++) { // steps[i] = (s16)MAX(wave_max - step * i, wave_min); // } // al_assert(steps[pixel_height] == wave_min); // // s64 rms = 0; // s16 min, max; // s16 low, high; // s16 *data = (s16 *)entry->raw.data; // const u32 samples_stride = samples_per_column * channels; // u16 masks_for_chars[height]; // //u32 slen[height]; // //al_memset(slen, 0, sizeof(u32) * height); // for (u32 i = 0; i < width; i++) { // al_memset(masks_for_chars, 0, sizeof(u16) * height); // for (u32 k = 0; k < 2; k++) { // u32 f = (i * 2 + k) * samples_stride; // for (u32 n = 0; n < channels; n++) { // rms = 0; // min = wave_max, max = wave_min; // for (u32 m = 0; m <= samples_stride; m += channels) { // s16 ss = data[f + m + n]; // rms += ss * ss; // min = MIN(min, ss); // max = MAX(max, ss); // } // rms /= samples_per_column; // rms = sqrt(rms); // for (u32 j = 0; j < height; j++) { // for (u32 l = 0; l < 4; l++) { // u32 step = j * 4 + l; // low = steps[step + 1], high = steps[step]; // if (low < max && high >= min) { // if (include_rms && WITHIN_RMS(low, high, rms)) { // masks_for_chars[j] |= RMS_BIT; // } else { // masks_for_chars[j] |= 1 << (l * 2 + k); // } // } // } // } // } // } // for (u32 j = 0; j < height; j++) { // if (masks_for_chars[j] & RMS_BIT) { // buf[j][i][0] = 'R'; // masks_for_chars[j] &= ~RMS_BIT; // } // u32 len = (masks_for_chars[j] == 0) ? 2 : 5; // al_memcpy(buf[j][i] + 1, octant_lut[masks_for_chars[j]], len); // //slen[j] += len; // } // } // // /* // for (u32 j = 0; j < height; j++) { // buf[j][slen[j]] = '\0'; // } // */ }