Remove outer frames

This commit is contained in:
Armin 2026-07-03 20:52:11 +02:00
commit 422a758cb2

187
tcd.c
View file

@ -435,9 +435,7 @@ static void repeat_str(const char *s, int n)
static void draw_hline(int width)
{
printf(ANSI_BLUE "" ANSI_RESET);
printf(ANSI_BLUE); repeat_str("", width); printf(ANSI_RESET);
printf(ANSI_BLUE "" ANSI_RESET);
printf("\n");
}
@ -468,7 +466,6 @@ static void freq_label_row(int chart_w, double nyquist)
}
}
printf(ANSI_BLUE "" ANSI_RESET);
int p = 0;
for (int i = 0; i < chart_w; i++) {
if (p < n_keep && i == pos[keep[p]]) {
@ -478,10 +475,8 @@ static void freq_label_row(int chart_w, double nyquist)
putchar(' ');
}
}
printf(ANSI_BLUE "" ANSI_RESET);
printf("\n");
printf(ANSI_BLUE "" ANSI_RESET);
p = 0;
for (int i = 0; i < chart_w; i++) {
if (p < n_keep && i == pos[keep[p]]) {
@ -494,7 +489,6 @@ static void freq_label_row(int chart_w, double nyquist)
putchar(' ');
}
}
printf(ANSI_BLUE "" ANSI_RESET);
printf("\n");
}
@ -517,7 +511,7 @@ static void render_visual_spectrum(
double nyquist = sample_rate / 2.0;
int label_w = 7;
int chart_w = term_w - label_w - 2;
int chart_w = term_w - label_w;
if (chart_w < 20) chart_w = 20;
double *spec = malloc(n_bins * sizeof(double));
@ -555,20 +549,13 @@ static void render_visual_spectrum(
int n_rows = 8;
double db_step = (db_max - db_min) / n_rows;
/* ============================ */
/* TOP BORDER */
/* ============================ */
printf(ANSI_BLUE "" ANSI_RESET);
printf(ANSI_BLUE); repeat_str("", chart_w + label_w); printf(ANSI_RESET);
printf(ANSI_BLUE "" ANSI_RESET "\n");
/* --- Title bar --- */
char title[256];
const char *short_name = strrchr(filename, '/');
short_name = short_name ? short_name + 1 : filename;
int info_len = snprintf(title, sizeof(title), " %s | %s | %d Hz | %d ch",
short_name, fmt_name, sample_rate, channels);
int total_w = term_w - 2;
int total_w = term_w;
if (info_len > total_w) {
char truncated[256];
snprintf(truncated, sizeof(truncated), " %s | %d Hz | %d ch",
@ -582,15 +569,11 @@ static void render_visual_spectrum(
}
}
}
printf(ANSI_BLUE "" ANSI_RESET);
printf(ANSI_BOLD ANSI_CYAN "%s" ANSI_RESET, truncated);
repeat_char(' ', total_w - (int)strlen(truncated));
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
} else {
printf(ANSI_BLUE "" ANSI_RESET);
printf(ANSI_BOLD ANSI_CYAN "%s" ANSI_RESET, title);
repeat_char(' ', total_w - info_len);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
}
draw_hline(chart_w + label_w);
@ -600,7 +583,6 @@ static void render_visual_spectrum(
/* ============================ */
for (int row = 0; row < n_rows; row++) {
double db_val = db_max - row * db_step;
printf(ANSI_BLUE "" ANSI_RESET);
printf(ANSI_DIM "%6.0f " ANSI_RESET, db_val);
for (int c = 0; c < chart_w; c++) {
@ -619,11 +601,10 @@ static void render_visual_spectrum(
printf("");
}
}
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
}
/* --- Cutoff arrow row --- */
printf(ANSI_BLUE "" ANSI_RESET);
repeat_char(' ', label_w);
for (int c = 0; c < chart_w; c++) {
if (c == cutoff_col) {
@ -632,7 +613,7 @@ static void render_visual_spectrum(
putchar(' ');
}
}
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
/* --- Cutoff label --- */
char cutoff_label[64];
@ -648,13 +629,12 @@ static void render_visual_spectrum(
if (label_start < 0) label_start = 0;
if (label_start + clen > chart_w) label_start = chart_w - clen;
printf(ANSI_BLUE "" ANSI_RESET);
repeat_char(' ', label_w);
repeat_char(' ', label_start);
printf(ANSI_YELLOW ANSI_BOLD "%s" ANSI_RESET, cutoff_label);
int remain = chart_w - label_start - clen;
if (remain > 0) repeat_char(' ', remain);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
/* --- Tick marks --- */
freq_label_row(chart_w, nyquist);
@ -667,23 +647,23 @@ static void render_visual_spectrum(
char peak_dbfs_str[32];
snprintf(peak_dbfs_str, sizeof(peak_dbfs_str), "%.1f", 20.0 * log10(peak));
printf(ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Peak:" ANSI_RESET " %7s dBFS " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Windows:" ANSI_RESET " %d " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "FFT:" ANSI_RESET " %d",
printf(" " ANSI_BOLD "Peak:" ANSI_RESET " %7s dBFS " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Windows:" ANSI_RESET " %d " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "FFT:" ANSI_RESET " %d",
peak_dbfs_str, analyzer_count, fft_size);
int used_metrics = 30 + 14 + 10 + 14;
repeat_char(' ', term_w - 2 - used_metrics);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
draw_hline(chart_w + label_w);
printf(ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Cutoff:" ANSI_RESET " %7.0f Hz (%5.1f%%) " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Steepness:" ANSI_RESET " %6.0f Hz " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Noise:" ANSI_RESET " %6.1f dB",
printf(" " ANSI_BOLD "Cutoff:" ANSI_RESET " %7.0f Hz (%5.1f%%) " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Steepness:" ANSI_RESET " %6.0f Hz " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Noise:" ANSI_RESET " %6.1f dB",
cutoff_hz, 100.0 * cutoff_hz / nyquist, steepness, noise_db);
repeat_char(' ', term_w - 2 - 62);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
printf(ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Roughness:" ANSI_RESET " %6.3f " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Band ratio:" ANSI_RESET " %6.3f",
printf(" " ANSI_BOLD "Roughness:" ANSI_RESET " %6.3f " ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Band ratio:" ANSI_RESET " %6.3f",
roughness, band_ratio);
repeat_char(' ', term_w - 2 - 36);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
/* ============================ */
/* DECISION / VALIDITY */
@ -694,7 +674,7 @@ static void render_visual_spectrum(
double confidence = compute_confidence(
cutoff_ratio, steepness, roughness, band_ratio, is_native_lossy);
printf(ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Decision:" ANSI_RESET " ");
printf(" " ANSI_BOLD "Decision:" ANSI_RESET " ");
if (peak_db < -90.0) {
printf(ANSI_RED "SILENT" ANSI_RESET " (no detectable audio content)");
} else if (is_native_lossy) {
@ -708,9 +688,7 @@ static void render_visual_spectrum(
else
printf(ANSI_GREEN "GENUINE" ANSI_RESET " (likely native lossless)");
}
int dlen = (int)strlen(" Decision: ") + 50;
repeat_char(' ', term_w - 2 - dlen);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
/* Validity bar */
int bar_w = 20;
@ -725,25 +703,20 @@ static void render_visual_spectrum(
else if (confidence >= 30) conf_label = "Weak evidence";
else conf_label = "Borderline / inconclusive";
printf(ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Validity:" ANSI_RESET " ");
printf(" " ANSI_BOLD "Validity:" ANSI_RESET " ");
for (int i = 0; i < bar_w; i++) {
if (i < filled) printf(ANSI_GREEN "" ANSI_RESET);
else printf(ANSI_DIM "" ANSI_RESET);
}
printf(ANSI_BOLD " %3.0f%%" ANSI_RESET, confidence);
printf(" \xe2\x80\x94 %s", conf_label);
int vlen = 12 + bar_w + 5 + 2 + (int)strlen(conf_label);
repeat_char(' ', term_w - 2 - vlen);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
printf(ANSI_BLUE "" ANSI_RESET);
repeat_char(' ', term_w - 2);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
/* --- Factor breakdown --- */
printf(ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Factors:" ANSI_RESET);
repeat_char(' ', term_w - 12);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf(" " ANSI_BOLD "Factors:" ANSI_RESET);
printf("\n");
if (is_native_lossy) {
if (upscaled) {
@ -751,22 +724,18 @@ static void render_visual_spectrum(
snprintf(line, sizeof(line),
" cutoff_ratio=%.3f < expected for bitrate (%lld kbps)",
cutoff_ratio, (long long)(bitrate / 1000));
printf(ANSI_BLUE "" ANSI_RESET " %s " ANSI_GREEN "" ANSI_RESET, line);
int remain = term_w - 4 - (int)strlen(line) - 2;
if (remain > 0) repeat_char(' ', remain);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf(" %s " ANSI_GREEN "" ANSI_RESET, line);
printf("\n");
const char *src_hint = "";
if (cutoff_ratio < 0.70) src_hint = "≤ 64 kbps source";
else if (cutoff_ratio < 0.80) src_hint = "96128 kbps source";
else if (cutoff_ratio < 0.88) src_hint = "128192 kbps source";
printf(ANSI_BLUE "" ANSI_RESET "" ANSI_BOLD "Suggest %s" ANSI_RESET, src_hint);
repeat_char(' ', term_w - 4 - (int)strlen(src_hint) - 14);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("" ANSI_BOLD "Suggest %s" ANSI_RESET, src_hint);
printf("\n");
} else {
printf(ANSI_BLUE "" ANSI_RESET " cutoff_ratio=%.3f within expected range for this bitrate " ANSI_GREEN "" ANSI_RESET, cutoff_ratio);
repeat_char(' ', term_w - 2 - 68);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf(" cutoff_ratio=%.3f within expected range for this bitrate " ANSI_GREEN "" ANSI_RESET, cutoff_ratio);
printf("\n");
}
} else {
double max_bw_display;
@ -786,81 +755,63 @@ static void render_visual_spectrum(
int secondary_applies = (cutoff_ratio > 0.80);
if (cutoff_ratio >= 0.99) {
printf(ANSI_BLUE "" ANSI_RESET " ① cutoff_ratio=%.3f ≥ 0.99 " ANSI_RED "" ANSI_RESET " (full spectrum, no cutoff)", cutoff_ratio);
repeat_char(' ', term_w - 2 - 62);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf(" ① cutoff_ratio=%.3f ≥ 0.99 " ANSI_RED "" ANSI_RESET " (full spectrum, no cutoff)", cutoff_ratio);
printf("\n");
} else {
char bw_label[64];
snprintf(bw_label, sizeof(bw_label), "transition_bw=%.0fHz < %.0fHz threshold",
steepness, max_bw_display);
if (primary_hit) {
printf(ANSI_BLUE "" ANSI_RESET " ① cutoff_ratio=%.3f, %s " ANSI_GREEN "" ANSI_RESET,
printf(" ① cutoff_ratio=%.3f, %s " ANSI_GREEN "" ANSI_RESET,
cutoff_ratio, bw_label);
repeat_char(' ', term_w - 2 - (int)strlen(bw_label) - 24);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
} else {
printf(ANSI_BLUE "" ANSI_RESET " ① cutoff_ratio=%.3f, transition_bw=%.0fHz ≥ %.0fHz threshold " ANSI_RED "" ANSI_RESET,
printf(" ① cutoff_ratio=%.3f, transition_bw=%.0fHz ≥ %.0fHz threshold " ANSI_RED "" ANSI_RESET,
cutoff_ratio, steepness, max_bw_display);
repeat_char(' ', term_w - 2 - 71);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
}
}
if (primary_hit) {
printf(ANSI_BLUE "" ANSI_RESET "" ANSI_YELLOW "Transition bandwidth indicates transcode" ANSI_RESET);
repeat_char(' ', term_w - 2 - 44);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("" ANSI_YELLOW "Transition bandwidth indicates transcode" ANSI_RESET);
printf("\n");
}
if (secondary_applies) {
int sec_hit = 0;
if (roughness > 0.40) {
printf(ANSI_BLUE "" ANSI_RESET " ② roughness=%.3f > 0.40 " ANSI_GREEN "" ANSI_RESET " (high roughness → transcode)", roughness);
repeat_char(' ', term_w - 2 - 60);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf(" ② roughness=%.3f > 0.40 " ANSI_GREEN "" ANSI_RESET " (high roughness → transcode)", roughness);
printf("\n");
sec_hit = 1;
} else if (roughness > 0.30 && band_ratio < 0.90) {
printf(ANSI_BLUE "" ANSI_RESET " ② roughness=%.3f > 0.30 " ANSI_GREEN "" ANSI_RESET " band_ratio=%.3f < 0.90 " ANSI_GREEN "" ANSI_RESET,
printf(" ② roughness=%.3f > 0.30 " ANSI_GREEN "" ANSI_RESET " band_ratio=%.3f < 0.90 " ANSI_GREEN "" ANSI_RESET,
roughness, band_ratio);
repeat_char(' ', term_w - 2 - 62);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
sec_hit = 1;
} else if (roughness > 0.20 && band_ratio < 0.85) {
printf(ANSI_BLUE "" ANSI_RESET " ② roughness=%.3f > 0.20 " ANSI_GREEN "" ANSI_RESET " band_ratio=%.3f < 0.85 " ANSI_GREEN "" ANSI_RESET,
printf(" ② roughness=%.3f > 0.20 " ANSI_GREEN "" ANSI_RESET " band_ratio=%.3f < 0.85 " ANSI_GREEN "" ANSI_RESET,
roughness, band_ratio);
repeat_char(' ', term_w - 2 - 62);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
sec_hit = 1;
}
if (sec_hit) {
printf(ANSI_BLUE "" ANSI_RESET "" ANSI_YELLOW "Secondary criteria triggered: transcode confirmed" ANSI_RESET);
repeat_char(' ', term_w - 2 - 52);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("" ANSI_YELLOW "Secondary criteria triggered: transcode confirmed" ANSI_RESET);
printf("\n");
} else if (!primary_hit) {
printf(ANSI_BLUE "" ANSI_RESET " ② Secondary: roughness=%.3f, band_ratio=%.3f " ANSI_RED "" ANSI_RESET,
printf(" ② Secondary: roughness=%.3f, band_ratio=%.3f " ANSI_RED "" ANSI_RESET,
roughness, band_ratio);
repeat_char(' ', term_w - 2 - 56);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf(ANSI_BLUE "" ANSI_RESET "" ANSI_GREEN "No transcode criteria met: genuine lossless" ANSI_RESET);
repeat_char(' ', term_w - 2 - 46);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
printf("" ANSI_GREEN "No transcode criteria met: genuine lossless" ANSI_RESET);
printf("\n");
}
} else if (!primary_hit) {
printf(ANSI_BLUE "" ANSI_RESET "" ANSI_GREEN "No transcode criteria met: genuine lossless" ANSI_RESET);
repeat_char(' ', term_w - 2 - 46);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("" ANSI_GREEN "No transcode criteria met: genuine lossless" ANSI_RESET);
printf("\n");
}
}
/* ============================ */
/* BOTTOM BORDER */
/* ============================ */
printf(ANSI_BLUE "" ANSI_RESET);
printf(ANSI_BLUE); repeat_str("", chart_w + label_w); printf(ANSI_RESET);
printf(ANSI_BLUE "" ANSI_RESET "\n");
free(spec);
free(col_max);
}
@ -883,14 +834,13 @@ static int vis_len(const char *s)
return len;
}
static void pn(const char *s) { printf("%s", s); }
static void pl(const char *s, int w)
{
int sl = vis_len(s);
printf(ANSI_BLUE "" ANSI_RESET " %s", s);
int pad = w - 4 - sl;
printf(" %s", s);
int pad = w - 2 - sl;
if (pad > 0) repeat_char(' ', pad);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
}
static void print_help(const char *prog)
@ -898,8 +848,6 @@ static void print_help(const char *prog)
int tw = get_term_width();
if (tw < 60) tw = 80;
pn(ANSI_BLUE ""); repeat_str("", tw - 2); pn(ANSI_BLUE "" ANSI_RESET "\n");
pl("", tw);
{
char buf[256];
@ -907,10 +855,10 @@ static void print_help(const char *prog)
" \xe2\x80\x94 Transcode Detector "
"Psychoacoustic audio authenticity analysis");
int v = vis_len(buf);
printf(ANSI_BLUE "" ANSI_RESET " %s", buf);
int pad = tw - 4 - v;
printf(" %s", buf);
int pad = tw - 2 - v;
if (pad > 0) repeat_char(' ', pad);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
}
pl("", tw);
@ -922,23 +870,19 @@ static void print_help(const char *prog)
snprintf(buf, sizeof(buf),
ANSI_BOLD "Usage:" ANSI_RESET " %s [options] [<audio-file> ...]", prog);
int v = vis_len(buf);
printf(ANSI_BLUE "" ANSI_RESET " %s", buf);
int pad = tw - 4 - v;
printf(" %s", buf);
int pad = tw - 2 - v;
if (pad > 0) repeat_char(' ', pad);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf("\n");
}
pl("", tw);
pn(ANSI_BLUE "" ANSI_RESET " " ANSI_BOLD "Options:" ANSI_RESET);
repeat_char(' ', tw - 12);
pn(ANSI_BLUE "" ANSI_RESET "\n");
printf(" " ANSI_BOLD "Options:" ANSI_RESET);
printf("\n");
#define OPT(fmt, desc) do { \
printf(ANSI_BLUE "" ANSI_RESET " " ANSI_GREEN fmt ANSI_RESET " %s", desc); \
int v = 1 + 4 + (int)strlen(fmt) + 2 + vis_len(desc); \
int pad = tw - 1 - v; \
if (pad > 0) repeat_char(' ', pad); \
printf(ANSI_BLUE "" ANSI_RESET "\n"); \
printf(" " ANSI_GREEN fmt ANSI_RESET " %s", desc); \
printf("\n"); \
} while (0)
{
@ -949,11 +893,8 @@ static void print_help(const char *prog)
{
char buf[80];
snprintf(buf, sizeof(buf), ANSI_DIM " Lower = fewer, higher = more" ANSI_RESET);
int v = 1 + 4 + vis_len(buf);
printf(ANSI_BLUE "" ANSI_RESET " %s", buf);
int pad = tw - 1 - v;
if (pad > 0) repeat_char(' ', pad);
printf(ANSI_BLUE "" ANSI_RESET "\n");
printf(" %s", buf);
printf("\n");
}
{
char buf[80];
@ -974,8 +915,6 @@ static void print_help(const char *prog)
OPT("-h, --help", "Show this help screen");
#undef OPT
pn(ANSI_BLUE ""); repeat_str("", tw - 2); pn(ANSI_BLUE "" ANSI_RESET "\n");
}
static void maybe_remove(const char *filename, int peak_db_neg90,