Carte che volano: dalla mano al tavolo e, finita la presa, sul mucchietto di chi ha preso (briscola, tressette, scopa; Andrea: «non si capisce quando vengono buttate le carte»). Il valzer della balera ai tavoli da carte (tools/valzer_carte.py: fisarmonica musette, basso, melodia di mandolino col tremolo), musica per primo piano; video «Come si gioca»: cache del Chromium della VM spenta, narratore e personaggi a turno, musica di sottofondo, pronunce del narratore
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1dxvtsZx8NE9fwjXUNDBr
This commit is contained in:
+24
-1
@@ -22,10 +22,16 @@ OUT = VIDEO / "out"
|
||||
# Area del gioco nello schermo della VM (Chromium a tutto schermo, zoom 125 %): misurata con «convert -trim».
|
||||
TAGLIO = "crop=1044:760:278:70"
|
||||
FASCIA = 110 # px sopra il gioco per le didascalie
|
||||
# I video «Come si gioca» (--tutorial): ai tavoli la pagina usa tutta l'altezza, comandi sotto compresi; didascalie
|
||||
# lunghe anche su tre righe.
|
||||
TAGLIO_TUTORIAL = "crop=1046:900:268:0"
|
||||
FASCIA_TUTORIAL = 132
|
||||
FONDO = "0x1B1420" # il colore di fondo della pagina del gioco
|
||||
VOLUME = 0.5 # musica della demo-prototipo (senza voci)
|
||||
VOLUME_SOTTO = 0.22 # musica sotto le voci: bassa (Andrea, 25 ottobre)
|
||||
VOLUME_VOCI = 1.0
|
||||
VOLUME_NARRATORE = 1.15
|
||||
VOLUME_TUTORIAL = 0.07 # musica dei video «Come si gioca»: sottofondo # il narratore dei video «Come si gioca», sopra la musica bassa
|
||||
FADE = 1.2
|
||||
|
||||
|
||||
@@ -42,6 +48,8 @@ def ts(s: float) -> str:
|
||||
|
||||
def main() -> None:
|
||||
d = Path(sys.argv[1]).expanduser()
|
||||
tutorial = "--tutorial" in sys.argv[2:]
|
||||
taglio, fascia = (TAGLIO_TUTORIAL, FASCIA_TUTORIAL) if tutorial else (TAGLIO, FASCIA)
|
||||
meta = json.loads((d / "cues.json").read_text())
|
||||
nome = meta["clip"]
|
||||
registro = OUT / f"{nome}-audio.json"
|
||||
@@ -59,6 +67,10 @@ def main() -> None:
|
||||
aperta["fine"] = e["t"]
|
||||
aperta = None
|
||||
volume = VOLUME_SOTTO
|
||||
# Nei video «Come si gioca» parla il narratore quasi sempre: la musica resta un sottofondo (Andrea, 26 ottobre:
|
||||
# «troppo alta la musica del gioco»).
|
||||
if (OUT / f"{nome}-narrazione.json").exists():
|
||||
volume = VOLUME_TUTORIAL
|
||||
else:
|
||||
musica = json.loads((OUT / "musica.json").read_text())
|
||||
volume = VOLUME
|
||||
@@ -105,9 +117,20 @@ def main() -> None:
|
||||
lungo = f"atrim=0:{v['fine'] - v['t'] + 0.1:.3f}," if "fine" in v else ""
|
||||
catene.append(f"[{n}:a]{lungo}asetpts=PTS-STARTPTS,volume={VOLUME_VOCI},adelay={int((v['t'] + scarto) * 1000)}:all=1[v{len(pezzi)}]")
|
||||
pezzi.append(f"[v{len(pezzi)}]")
|
||||
# Il narratore dei video «Come si gioca» (video/narra.py): ogni frase all'inizio della sua battuta.
|
||||
narrazione = OUT / f"{nome}-narrazione.json"
|
||||
if narrazione.exists():
|
||||
frasi = {v["id"]: v["src"] for v in json.loads(narrazione.read_text())["voci"]}
|
||||
for c in cues:
|
||||
if c["id"] not in frasi:
|
||||
continue
|
||||
ingressi += ["-i", str(GIOCO / frasi[c["id"]])]
|
||||
n = ingressi.count("-i")
|
||||
catene.append(f"[{n}:a]asetpts=PTS-STARTPTS,volume={VOLUME_NARRATORE},adelay={int((c['start'] + scarto) * 1000)}:all=1[n{len(pezzi)}]")
|
||||
pezzi.append(f"[n{len(pezzi)}]")
|
||||
mix = "".join(pezzi) + f"amix=inputs={len(pezzi)}:normalize=0:duration=longest[a]"
|
||||
stile = f"FontName=DejaVu Sans,FontSize=11,Bold=1,MarginV=4,Outline=1,Shadow=0,PrimaryColour=&H007AD2FF"
|
||||
video = f"[0:v]{TAGLIO},pad=iw:ih+{FASCIA}:0:{FASCIA}:{FONDO},subtitles={srt}:force_style='{stile}'[v]"
|
||||
video = f"[0:v]{taglio},pad=iw:ih+{fascia}:0:{fascia}:{FONDO},subtitles={srt}:force_style='{stile}'[v]"
|
||||
finale = OUT / f"{nome}.mp4"
|
||||
subprocess.run(["ffmpeg", "-loglevel", "error", "-y", "-i", str(raw), *ingressi,
|
||||
"-filter_complex", ";".join([video, *catene, mix]), "-map", "[v]", "-map", "[a]",
|
||||
|
||||
Reference in New Issue
Block a user