Setting the file. One moment.
Transcript Cut Test · Media Use · heygen-com/hyperframes · Skills Docs
ContentsBack to the top of the page ⋯
scripts/11 files
scripts/transcript-cut.test.mjs
scripts/ transcript-cut.test.mjs
JavaScript · 117 lines · 4 KB
from
"node:url"
;
8
9 const SCRIPT = fileURLToPath ( new URL ( "./transcript-cut.mjs" , import . meta .url));
10 const HAS_FFMPEG =
11 spawnSync ( "ffmpeg" , [ "-version" ], { stdio: "ignore" }).status === 0 &&
12 spawnSync ( "ffprobe" , [ "-version" ], { stdio: "ignore" }).status === 0 ;
13
14 const SAMPLE_RATE = 44100 ;
15 // A continuous tone's own slope between samples never exceeds amplitude * 2*pi*f/rate
16 // (~2054 for 440Hz at full scale here); a raw splice between two independently-cut
17 // points on the same tone lands at two unrelated phases, so an unfaded join jumps far
18 // past that. This threshold sits well above normal tone motion and well below a splice.
19 const MAX_CONTINUOUS_STEP = 6000 ;
20 const MIN_SUSPICIOUS_ZERO_RUN = 20 ;
21
22 function fixture () {
23 const dir = mkdtempSync ( join ( tmpdir (), "media-use-transcript-cut-" ));
24 return { dir, cleanup : () => rmSync (dir, { recursive: true , force: true }) };
25 }
26
27 function run ( args ) {
28 return spawnSync (process.execPath, [ SCRIPT , ... args], { encoding: "utf8" });
29 }
30
31 function readPcm ( filePath ) {
32 const raw = execFileSync ( "ffmpeg" , [
33 "-hide_banner" ,
34 "-loglevel" ,
35 "error" ,
36 "-i" ,
37 filePath,
38 "-f" ,
39 "s16le" ,
40 "-ac" ,
41 "1" ,
42 "-ar" ,
43 String ( SAMPLE_RATE ),
44 "-" ,
45 ]);
46 const samples = new Int16Array (raw.buffer, raw.byteOffset, raw. length / 2 );
47 return samples;
48 }
49
50 test (
51 "keeps a spliced tone continuous at every cut, with no raw phase jump or silence gap" ,
52 { skip: ! HAS_FFMPEG },
53 ( t ) => {
54 const { dir , cleanup } = fixture ();
55 t. after (cleanup);
56
57 const source = join (dir, "tone.wav" );
58 execFileSync ( "ffmpeg" , [
59 "-y" ,
60 "-hide_banner" ,
61 "-loglevel" ,
62 "error" ,
63 "-f" ,
64 "lavfi" ,
65 "-i" ,
66 `sine=frequency=440:duration=6:sample_rate=${ SAMPLE_RATE }` ,
67 source,
68 ]);
69
70 const transcriptPath = join (dir, "transcript.json" );
71 writeFileSync (transcriptPath, JSON . stringify ({ words: [{ text: "tone" , start: 0 , end: 6 }] }));
72
73 const output = join (dir, "out.wav" );
74 // Two "ugly" removal ranges: neither aligned to the 440Hz period, so the kept
75 // segments' cut edges land at unrelated phases of the same continuous tone --
76 // exactly the shape that clicks without a fade, and the shape jrusso1020's
77 // review proved this branch never actually fades.
78 const result = run ([
79 "--input" ,
80 source,
81 "--transcript" ,
82 transcriptPath,
83 "--remove" ,
84 "1.37-1.83,3.29-3.71" ,
85 "--out" ,
86 output,
87 "--json" ,
88 ]);
89 assert. equal (result.status, 0 , result.stderr || result.stdout);
90
91 const samples = readPcm (output);
92 assert. ok (samples. length > SAMPLE_RATE , "expected several seconds of audio" );
93
94 let maxStep = 0 ;
95 let zeroRun = 0 ;
96 let maxZeroRun = 0 ;
97 for ( let i = 1 ; i < samples. length ; i ++ ) {
98 const step = Math. abs (samples[i] - samples[i - 1 ]);
99 if (step > maxStep) maxStep = step;
100 if (samples[i] === 0 ) {
101 zeroRun ++ ;
102 if (zeroRun > maxZeroRun) maxZeroRun = zeroRun;
103 } else {
104 zeroRun = 0 ;
105 }
106 }
107
108 assert. ok (
109 maxStep <= MAX_CONTINUOUS_STEP ,
110 `largest sample-to-sample step was ${ maxStep }, expected <= ${ MAX_CONTINUOUS_STEP } (a raw, unfaded splice)` ,
111 );
112 assert. ok (
113 maxZeroRun < MIN_SUSPICIOUS_ZERO_RUN ,
114 `found a run of ${ maxZeroRun } consecutive zero samples, expected < ${ MIN_SUSPICIOUS_ZERO_RUN } (a priming-silence gap)` ,
115 );
116 },
117 );