Cut the shots where the clock says, not where a word count guesses
"I am not" and "extraordinarily unimpressed" are both three words and nowhere near the same length, so any word budget is a guess about something we can measure. Three attempts at tuning one were wrong in both directions. Speaking the monologue once returns the start and end of every character, so word boundaries are exact. This cuts each shot at the word whose end sits nearest the boundary, preferring a sentence ending when one is close. On the first real test it produced a 20 word shot landing at 7.8s and cutting on a full stop, where the budget had said 18.
This commit is contained in:
parent
c26efbbea7
commit
4d553585d6
1 changed files with 67 additions and 0 deletions
67
script.html
67
script.html
|
|
@ -377,7 +377,12 @@ function render(r) {
|
||||||
+ 'words costs about a hundredth of a cent. Run it through in your pet’s voice '
|
+ 'words costs about a hundredth of a cent. Run it through in your pet’s voice '
|
||||||
+ 'over the opening stills first, and only film once the timing and the jokes land.</p>'
|
+ 'over the opening stills first, and only film once the timing and the jokes land.</p>'
|
||||||
+ '<button type="button" class="btn ghost" id="pzmake">Speak the script</button>'
|
+ '<button type="button" class="btn ghost" id="pzmake">Speak the script</button>'
|
||||||
|
+ '<button type="button" class="btn" id="alignbtn" style="margin-left:8px">Cut it to the clock</button>'
|
||||||
+ '<span class="foot" style="margin-left:12px" id="pznote"></span>'
|
+ '<span class="foot" style="margin-left:12px" id="pznote"></span>'
|
||||||
|
+ '<p class="foot" style="margin:10px 0 0">Cutting to the clock speaks the whole piece once, '
|
||||||
|
+ 'measures where every word actually falls, and moves the shot boundaries to real word '
|
||||||
|
+ 'endings. It rewrites how the lines are divided — not the words themselves.</p>'
|
||||||
|
+ '<div id="alignout" style="margin-top:14px"></div>'
|
||||||
+ '<div id="pzout" style="margin-top:16px"></div>'
|
+ '<div id="pzout" style="margin-top:16px"></div>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '<h2 class="sec" style="margin-top:34px">The shots</h2>'
|
+ '<h2 class="sec" style="margin-top:34px">The shots</h2>'
|
||||||
|
|
@ -531,6 +536,7 @@ function wire(locked) {
|
||||||
});
|
});
|
||||||
bindPics();
|
bindPics();
|
||||||
bindPreviz();
|
bindPreviz();
|
||||||
|
bindAlign();
|
||||||
bindFilm((DATA && DATA.project) || {});
|
bindFilm((DATA && DATA.project) || {});
|
||||||
bindPost();
|
bindPost();
|
||||||
if (locked) { bindBottom(); return; }
|
if (locked) { bindBottom(); return; }
|
||||||
|
|
@ -1013,6 +1019,67 @@ function pzPaint(lines) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bindAlign() {
|
||||||
|
var b = document.getElementById("alignbtn");
|
||||||
|
if (!b) return;
|
||||||
|
var out = document.getElementById("alignout");
|
||||||
|
|
||||||
|
function paint(r) {
|
||||||
|
var bought = ((DATA && DATA.script && DATA.script.segments) || []).length * 8;
|
||||||
|
var filmed = r.filmed || 0;
|
||||||
|
out.innerHTML = '<p class="foot" style="margin:0 0 8px">Measured: '
|
||||||
|
+ (r.spoken || 0).toFixed(1) + 's spoken, about ' + filmed.toFixed(1)
|
||||||
|
+ 's filmed, against ' + bought + 's of shots.</p>'
|
||||||
|
+ (r.audio ? '<audio controls src="' + esc(r.audio) + '" style="width:100%;max-width:420px"></audio>' : '')
|
||||||
|
+ (r.shots || []).map(function (s) {
|
||||||
|
var fit = Math.abs((s.filmed || 0) - 8) <= 1.2;
|
||||||
|
return '<div class="foot" style="padding:6px 0;border-top:1px solid var(--line)">'
|
||||||
|
+ 'shot ' + s.index + ' · ' + (s.start || 0).toFixed(1) + '-'
|
||||||
|
+ (s.end || 0).toFixed(1) + 's spoken · ~' + (s.filmed || 0).toFixed(1) + 's filmed'
|
||||||
|
+ (fit ? '' : ' <span style="color:var(--accent2)">off the clock</span>')
|
||||||
|
+ '<br>' + esc(s.line || "") + '</div>';
|
||||||
|
}).join("")
|
||||||
|
+ (filmed < bought - 1.5
|
||||||
|
? '<div class="warn" style="margin-top:12px">The whole piece only runs about '
|
||||||
|
+ filmed.toFixed(1) + ' seconds filmed, but ' + bought + ' seconds are being shot. '
|
||||||
|
+ 'No arrangement of these words fills the video — it needs more written, or a '
|
||||||
|
+ 'shorter length.</div>'
|
||||||
|
: '')
|
||||||
|
+ (filmed > bought + 1.5
|
||||||
|
? '<div class="warn" style="margin-top:12px">The whole piece runs about '
|
||||||
|
+ filmed.toFixed(1) + ' seconds filmed against ' + bought + ' seconds of video, so the '
|
||||||
|
+ 'end would be cut off. Trim it, or buy more length.</div>'
|
||||||
|
: '');
|
||||||
|
}
|
||||||
|
|
||||||
|
b.onclick = async function () {
|
||||||
|
hideMsg("msg");
|
||||||
|
b.disabled = true; b.textContent = "Measuring…";
|
||||||
|
var r = await api("align_script", { email: email, project_id: pid, refresh: true });
|
||||||
|
if (r.ok && r.pending) {
|
||||||
|
var waited = 0;
|
||||||
|
r = await new Promise(function (done) {
|
||||||
|
var t = setInterval(async function () {
|
||||||
|
waited += 4;
|
||||||
|
var g = await api("align_script", { email: email, project_id: pid });
|
||||||
|
if (g.ok && !g.pending) { clearInterval(t); done(g); return; }
|
||||||
|
if (waited > 240) { clearInterval(t); done({ ok: false, error: "That is taking unusually long." }); }
|
||||||
|
}, 4000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
b.disabled = false; b.textContent = "Cut it to the clock";
|
||||||
|
if (!r.ok) { showMsg("msg", r.error || "Could not measure that."); return; }
|
||||||
|
if (r.note) { showMsg("msg", r.note); return; }
|
||||||
|
paint(r);
|
||||||
|
showMsg("msg", "Shots re-cut at real word endings.", "ok");
|
||||||
|
load();
|
||||||
|
};
|
||||||
|
|
||||||
|
api("align_script", { email: email, project_id: pid }).then(function (r) {
|
||||||
|
if (r && r.ok && !r.pending && r.audio) paint(r);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function bindPreviz() {
|
function bindPreviz() {
|
||||||
var b = document.getElementById("pzmake");
|
var b = document.getElementById("pzmake");
|
||||||
if (!b) return;
|
if (!b) return;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue