venice-video-harness 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +598 -0
- package/dist/assembly/manifest-builder.d.ts +8 -0
- package/dist/assembly/manifest-builder.d.ts.map +1 -0
- package/dist/assembly/manifest-builder.js +196 -0
- package/dist/assembly/manifest-builder.js.map +1 -0
- package/dist/assembly/remotion-scaffold.d.ts +14 -0
- package/dist/assembly/remotion-scaffold.d.ts.map +1 -0
- package/dist/assembly/remotion-scaffold.js +292 -0
- package/dist/assembly/remotion-scaffold.js.map +1 -0
- package/dist/assembly/types.d.ts +67 -0
- package/dist/assembly/types.d.ts.map +1 -0
- package/dist/assembly/types.js +5 -0
- package/dist/assembly/types.js.map +1 -0
- package/dist/characters/describer.d.ts +32 -0
- package/dist/characters/describer.d.ts.map +1 -0
- package/dist/characters/describer.js +309 -0
- package/dist/characters/describer.js.map +1 -0
- package/dist/characters/extractor.d.ts +27 -0
- package/dist/characters/extractor.d.ts.map +1 -0
- package/dist/characters/extractor.js +274 -0
- package/dist/characters/extractor.js.map +1 -0
- package/dist/characters/reference-manager.d.ts +95 -0
- package/dist/characters/reference-manager.d.ts.map +1 -0
- package/dist/characters/reference-manager.js +346 -0
- package/dist/characters/reference-manager.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +310 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +66 -0
- package/dist/config.js.map +1 -0
- package/dist/editing/aligner.d.ts +44 -0
- package/dist/editing/aligner.d.ts.map +1 -0
- package/dist/editing/aligner.js +201 -0
- package/dist/editing/aligner.js.map +1 -0
- package/dist/editing/edl.d.ts +45 -0
- package/dist/editing/edl.d.ts.map +1 -0
- package/dist/editing/edl.js +133 -0
- package/dist/editing/edl.js.map +1 -0
- package/dist/editing/overlays.d.ts +97 -0
- package/dist/editing/overlays.d.ts.map +1 -0
- package/dist/editing/overlays.js +41 -0
- package/dist/editing/overlays.js.map +1 -0
- package/dist/editing/packer.d.ts +52 -0
- package/dist/editing/packer.d.ts.map +1 -0
- package/dist/editing/packer.js +170 -0
- package/dist/editing/packer.js.map +1 -0
- package/dist/editing/providers/whisper-cpp.d.ts +32 -0
- package/dist/editing/providers/whisper-cpp.d.ts.map +1 -0
- package/dist/editing/providers/whisper-cpp.js +239 -0
- package/dist/editing/providers/whisper-cpp.js.map +1 -0
- package/dist/editing/render.d.ts +36 -0
- package/dist/editing/render.d.ts.map +1 -0
- package/dist/editing/render.js +227 -0
- package/dist/editing/render.js.map +1 -0
- package/dist/editing/self-eval.d.ts +48 -0
- package/dist/editing/self-eval.d.ts.map +1 -0
- package/dist/editing/self-eval.js +293 -0
- package/dist/editing/self-eval.js.map +1 -0
- package/dist/editing/silence.d.ts +76 -0
- package/dist/editing/silence.d.ts.map +1 -0
- package/dist/editing/silence.js +189 -0
- package/dist/editing/silence.js.map +1 -0
- package/dist/editing/types.d.ts +178 -0
- package/dist/editing/types.d.ts.map +1 -0
- package/dist/editing/types.js +13 -0
- package/dist/editing/types.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/interactive.d.ts +12 -0
- package/dist/interactive.d.ts.map +1 -0
- package/dist/interactive.js +78 -0
- package/dist/interactive.js.map +1 -0
- package/dist/mini-drama/assembler.d.ts +61 -0
- package/dist/mini-drama/assembler.d.ts.map +1 -0
- package/dist/mini-drama/assembler.js +466 -0
- package/dist/mini-drama/assembler.js.map +1 -0
- package/dist/mini-drama/audio-mix.d.ts +65 -0
- package/dist/mini-drama/audio-mix.d.ts.map +1 -0
- package/dist/mini-drama/audio-mix.js +118 -0
- package/dist/mini-drama/audio-mix.js.map +1 -0
- package/dist/mini-drama/cli.d.ts +3 -0
- package/dist/mini-drama/cli.d.ts.map +1 -0
- package/dist/mini-drama/cli.js +2869 -0
- package/dist/mini-drama/cli.js.map +1 -0
- package/dist/mini-drama/fcpxml-export.d.ts +2 -0
- package/dist/mini-drama/fcpxml-export.d.ts.map +1 -0
- package/dist/mini-drama/fcpxml-export.js +5 -0
- package/dist/mini-drama/fcpxml-export.js.map +1 -0
- package/dist/mini-drama/generation-planner.d.ts +24 -0
- package/dist/mini-drama/generation-planner.d.ts.map +1 -0
- package/dist/mini-drama/generation-planner.js +304 -0
- package/dist/mini-drama/generation-planner.js.map +1 -0
- package/dist/mini-drama/location-generator.d.ts +23 -0
- package/dist/mini-drama/location-generator.d.ts.map +1 -0
- package/dist/mini-drama/location-generator.js +144 -0
- package/dist/mini-drama/location-generator.js.map +1 -0
- package/dist/mini-drama/music-cues.d.ts +96 -0
- package/dist/mini-drama/music-cues.d.ts.map +1 -0
- package/dist/mini-drama/music-cues.js +332 -0
- package/dist/mini-drama/music-cues.js.map +1 -0
- package/dist/mini-drama/panel-fixer.d.ts +12 -0
- package/dist/mini-drama/panel-fixer.d.ts.map +1 -0
- package/dist/mini-drama/panel-fixer.js +319 -0
- package/dist/mini-drama/panel-fixer.js.map +1 -0
- package/dist/mini-drama/prompt-builder.d.ts +149 -0
- package/dist/mini-drama/prompt-builder.d.ts.map +1 -0
- package/dist/mini-drama/prompt-builder.js +722 -0
- package/dist/mini-drama/prompt-builder.js.map +1 -0
- package/dist/mini-drama/reference-slots.d.ts +31 -0
- package/dist/mini-drama/reference-slots.d.ts.map +1 -0
- package/dist/mini-drama/reference-slots.js +161 -0
- package/dist/mini-drama/reference-slots.js.map +1 -0
- package/dist/mini-drama/shot-paths.d.ts +77 -0
- package/dist/mini-drama/shot-paths.d.ts.map +1 -0
- package/dist/mini-drama/shot-paths.js +101 -0
- package/dist/mini-drama/shot-paths.js.map +1 -0
- package/dist/mini-drama/storyboard-reference-generator.d.ts +47 -0
- package/dist/mini-drama/storyboard-reference-generator.d.ts.map +1 -0
- package/dist/mini-drama/storyboard-reference-generator.js +293 -0
- package/dist/mini-drama/storyboard-reference-generator.js.map +1 -0
- package/dist/mini-drama/subtitle-generator.d.ts +12 -0
- package/dist/mini-drama/subtitle-generator.d.ts.map +1 -0
- package/dist/mini-drama/subtitle-generator.js +139 -0
- package/dist/mini-drama/subtitle-generator.js.map +1 -0
- package/dist/mini-drama/timeline-export/davinci-fcpxml.d.ts +3 -0
- package/dist/mini-drama/timeline-export/davinci-fcpxml.d.ts.map +1 -0
- package/dist/mini-drama/timeline-export/davinci-fcpxml.js +150 -0
- package/dist/mini-drama/timeline-export/davinci-fcpxml.js.map +1 -0
- package/dist/mini-drama/timeline-export/fcpxml.d.ts +11 -0
- package/dist/mini-drama/timeline-export/fcpxml.d.ts.map +1 -0
- package/dist/mini-drama/timeline-export/fcpxml.js +140 -0
- package/dist/mini-drama/timeline-export/fcpxml.js.map +1 -0
- package/dist/mini-drama/timeline-export/index.d.ts +13 -0
- package/dist/mini-drama/timeline-export/index.d.ts.map +1 -0
- package/dist/mini-drama/timeline-export/index.js +26 -0
- package/dist/mini-drama/timeline-export/index.js.map +1 -0
- package/dist/mini-drama/timeline-export/premiere-xmeml.d.ts +3 -0
- package/dist/mini-drama/timeline-export/premiere-xmeml.d.ts.map +1 -0
- package/dist/mini-drama/timeline-export/premiere-xmeml.js +211 -0
- package/dist/mini-drama/timeline-export/premiere-xmeml.js.map +1 -0
- package/dist/mini-drama/timeline-export/probe.d.ts +53 -0
- package/dist/mini-drama/timeline-export/probe.d.ts.map +1 -0
- package/dist/mini-drama/timeline-export/probe.js +89 -0
- package/dist/mini-drama/timeline-export/probe.js.map +1 -0
- package/dist/mini-drama/timeline-export/types.d.ts +57 -0
- package/dist/mini-drama/timeline-export/types.d.ts.map +1 -0
- package/dist/mini-drama/timeline-export/types.js +14 -0
- package/dist/mini-drama/timeline-export/types.js.map +1 -0
- package/dist/mini-drama/video-generator.d.ts +22 -0
- package/dist/mini-drama/video-generator.d.ts.map +1 -0
- package/dist/mini-drama/video-generator.js +1305 -0
- package/dist/mini-drama/video-generator.js.map +1 -0
- package/dist/mini-drama/voice-reference.d.ts +42 -0
- package/dist/mini-drama/voice-reference.d.ts.map +1 -0
- package/dist/mini-drama/voice-reference.js +170 -0
- package/dist/mini-drama/voice-reference.js.map +1 -0
- package/dist/output/html-renderer.d.ts +2 -0
- package/dist/output/html-renderer.d.ts.map +1 -0
- package/dist/output/html-renderer.js +37 -0
- package/dist/output/html-renderer.js.map +1 -0
- package/dist/parsers/fountain-parser.d.ts +34 -0
- package/dist/parsers/fountain-parser.d.ts.map +1 -0
- package/dist/parsers/fountain-parser.js +71 -0
- package/dist/parsers/fountain-parser.js.map +1 -0
- package/dist/parsers/pdf-parser.d.ts +24 -0
- package/dist/parsers/pdf-parser.d.ts.map +1 -0
- package/dist/parsers/pdf-parser.js +237 -0
- package/dist/parsers/pdf-parser.js.map +1 -0
- package/dist/parsers/scene-extractor.d.ts +41 -0
- package/dist/parsers/scene-extractor.d.ts.map +1 -0
- package/dist/parsers/scene-extractor.js +400 -0
- package/dist/parsers/scene-extractor.js.map +1 -0
- package/dist/series/manager.d.ts +64 -0
- package/dist/series/manager.d.ts.map +1 -0
- package/dist/series/manager.js +282 -0
- package/dist/series/manager.js.map +1 -0
- package/dist/series/types.d.ts +641 -0
- package/dist/series/types.d.ts.map +1 -0
- package/dist/series/types.js +304 -0
- package/dist/series/types.js.map +1 -0
- package/dist/storyboard/assembler.d.ts +134 -0
- package/dist/storyboard/assembler.d.ts.map +1 -0
- package/dist/storyboard/assembler.js +319 -0
- package/dist/storyboard/assembler.js.map +1 -0
- package/dist/storyboard/prompt-builder.d.ts +113 -0
- package/dist/storyboard/prompt-builder.d.ts.map +1 -0
- package/dist/storyboard/prompt-builder.js +578 -0
- package/dist/storyboard/prompt-builder.js.map +1 -0
- package/dist/storyboard/shot-planner.d.ts +34 -0
- package/dist/storyboard/shot-planner.d.ts.map +1 -0
- package/dist/storyboard/shot-planner.js +446 -0
- package/dist/storyboard/shot-planner.js.map +1 -0
- package/dist/user-config.d.ts +15 -0
- package/dist/user-config.d.ts.map +1 -0
- package/dist/user-config.js +103 -0
- package/dist/user-config.js.map +1 -0
- package/dist/venice/audio-preflight.d.ts +80 -0
- package/dist/venice/audio-preflight.d.ts.map +1 -0
- package/dist/venice/audio-preflight.js +142 -0
- package/dist/venice/audio-preflight.js.map +1 -0
- package/dist/venice/audio.d.ts +88 -0
- package/dist/venice/audio.d.ts.map +1 -0
- package/dist/venice/audio.js +234 -0
- package/dist/venice/audio.js.map +1 -0
- package/dist/venice/client.d.ts +86 -0
- package/dist/venice/client.d.ts.map +1 -0
- package/dist/venice/client.js +375 -0
- package/dist/venice/client.js.map +1 -0
- package/dist/venice/edit.d.ts +57 -0
- package/dist/venice/edit.d.ts.map +1 -0
- package/dist/venice/edit.js +100 -0
- package/dist/venice/edit.js.map +1 -0
- package/dist/venice/generate.d.ts +47 -0
- package/dist/venice/generate.d.ts.map +1 -0
- package/dist/venice/generate.js +150 -0
- package/dist/venice/generate.js.map +1 -0
- package/dist/venice/image-bytes.d.ts +26 -0
- package/dist/venice/image-bytes.d.ts.map +1 -0
- package/dist/venice/image-bytes.js +101 -0
- package/dist/venice/image-bytes.js.map +1 -0
- package/dist/venice/models.d.ts +143 -0
- package/dist/venice/models.d.ts.map +1 -0
- package/dist/venice/models.js +984 -0
- package/dist/venice/models.js.map +1 -0
- package/dist/venice/multi-edit.d.ts +40 -0
- package/dist/venice/multi-edit.d.ts.map +1 -0
- package/dist/venice/multi-edit.js +97 -0
- package/dist/venice/multi-edit.js.map +1 -0
- package/dist/venice/provenance.d.ts +66 -0
- package/dist/venice/provenance.d.ts.map +1 -0
- package/dist/venice/provenance.js +151 -0
- package/dist/venice/provenance.js.map +1 -0
- package/dist/venice/recipe.d.ts +69 -0
- package/dist/venice/recipe.d.ts.map +1 -0
- package/dist/venice/recipe.js +103 -0
- package/dist/venice/recipe.js.map +1 -0
- package/dist/venice/rejection.d.ts +63 -0
- package/dist/venice/rejection.d.ts.map +1 -0
- package/dist/venice/rejection.js +111 -0
- package/dist/venice/rejection.js.map +1 -0
- package/dist/venice/seedance-preflight.d.ts +38 -0
- package/dist/venice/seedance-preflight.d.ts.map +1 -0
- package/dist/venice/seedance-preflight.js +29 -0
- package/dist/venice/seedance-preflight.js.map +1 -0
- package/dist/venice/types.d.ts +212 -0
- package/dist/venice/types.d.ts.map +1 -0
- package/dist/venice/types.js +9 -0
- package/dist/venice/types.js.map +1 -0
- package/dist/venice/video.d.ts +77 -0
- package/dist/venice/video.d.ts.map +1 -0
- package/dist/venice/video.js +163 -0
- package/dist/venice/video.js.map +1 -0
- package/dist/venice/voices.d.ts +40 -0
- package/dist/venice/voices.d.ts.map +1 -0
- package/dist/venice/voices.js +194 -0
- package/dist/venice/voices.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generation-planner.js","sourceRoot":"","sources":["../../src/mini-drama/generation-planner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { VeniceClient } from '../venice/client.js';
|
|
2
|
+
import type { Location, SeriesState } from '../series/types.js';
|
|
3
|
+
export declare const LOCATION_ANGLES: readonly ["wide", "medium", "detail"];
|
|
4
|
+
export type LocationAngle = (typeof LOCATION_ANGLES)[number];
|
|
5
|
+
export interface GenerateLocationReferencesOptions {
|
|
6
|
+
/** Override the image-generation model (default nano-banana-pro). */
|
|
7
|
+
model?: string;
|
|
8
|
+
/** cfg_scale (default 10). */
|
|
9
|
+
cfgScale?: number;
|
|
10
|
+
/** Regenerate angles that already exist on disk. */
|
|
11
|
+
force?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Generate the three reference angles for a location. Writes
|
|
15
|
+
* `locations/<slug>/{wide,medium,detail}.png` plus per-angle `.prompt.json`
|
|
16
|
+
* sidecars, provenance (hasFace:false), and recipe passes. Returns the paths
|
|
17
|
+
* that were (re)generated.
|
|
18
|
+
*/
|
|
19
|
+
export declare function generateLocationReferences(client: VeniceClient, series: SeriesState, location: Location, options?: GenerateLocationReferencesOptions): Promise<{
|
|
20
|
+
generated: string[];
|
|
21
|
+
skipped: string[];
|
|
22
|
+
}>;
|
|
23
|
+
//# sourceMappingURL=location-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"location-generator.d.ts","sourceRoot":"","sources":["../../src/mini-drama/location-generator.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAQhE,eAAO,MAAM,eAAe,uCAAwC,CAAC;AACrE,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAoB7D,MAAM,WAAW,iCAAiC;IAChD,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,QAAQ,EAClB,OAAO,GAAE,iCAAsC,GAC9C,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA0GrD"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Location Reference Generation
|
|
3
|
+
//
|
|
4
|
+
// Locations are first-class environment entities (see Location in
|
|
5
|
+
// src/series/types.ts). Their reference images anchor the environment across
|
|
6
|
+
// storyboard panels, starting frames, and video generations — mirroring how
|
|
7
|
+
// character references anchor identity, and directly serving the
|
|
8
|
+
// lighting-consistency anti-pattern (AGENTS.md anti-pattern 7).
|
|
9
|
+
//
|
|
10
|
+
// Reference angles: wide (establishing), medium (mid-distance), detail
|
|
11
|
+
// (distinctive feature). Generated FACELESS with nano-banana-pro (default) and
|
|
12
|
+
// provenance hasFace:false, so they pass the Seedance pre-flight gate without
|
|
13
|
+
// laundering. Shared by the `add-location` CLI command and workshop-episode's
|
|
14
|
+
// auto-extraction so both paths produce identical assets.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
import { join, basename } from 'node:path';
|
|
17
|
+
import { existsSync } from 'node:fs';
|
|
18
|
+
import { mkdir, writeFile, rename } from 'node:fs/promises';
|
|
19
|
+
import { getLocationDir } from '../series/manager.js';
|
|
20
|
+
import { generateImage } from '../venice/generate.js';
|
|
21
|
+
import { writeImageBytesSmart } from '../venice/image-bytes.js';
|
|
22
|
+
import { appendRecipePass } from '../venice/recipe.js';
|
|
23
|
+
import { DEFAULT_IMAGE_GENERATION_MODEL } from '../series/types.js';
|
|
24
|
+
export const LOCATION_ANGLES = ['wide', 'medium', 'detail'];
|
|
25
|
+
const ANGLE_PROMPTS = {
|
|
26
|
+
wide: 'wide establishing shot of the location, full environment visible, cinematic widescreen framing',
|
|
27
|
+
medium: 'medium shot of the location, mid-distance framing showing the key features and spatial layout',
|
|
28
|
+
detail: 'close detail shot of a distinctive feature of the location, texture and material detail',
|
|
29
|
+
};
|
|
30
|
+
function buildAestheticString(aesthetic) {
|
|
31
|
+
return [
|
|
32
|
+
aesthetic.style,
|
|
33
|
+
aesthetic.palette,
|
|
34
|
+
aesthetic.lighting,
|
|
35
|
+
aesthetic.lensCharacteristics,
|
|
36
|
+
aesthetic.filmStock ? `shot on ${aesthetic.filmStock}` : '',
|
|
37
|
+
]
|
|
38
|
+
.filter(Boolean)
|
|
39
|
+
.join(', ');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Generate the three reference angles for a location. Writes
|
|
43
|
+
* `locations/<slug>/{wide,medium,detail}.png` plus per-angle `.prompt.json`
|
|
44
|
+
* sidecars, provenance (hasFace:false), and recipe passes. Returns the paths
|
|
45
|
+
* that were (re)generated.
|
|
46
|
+
*/
|
|
47
|
+
export async function generateLocationReferences(client, series, location, options = {}) {
|
|
48
|
+
if (!series.aesthetic) {
|
|
49
|
+
throw new Error('Series aesthetic must be set before generating location references.');
|
|
50
|
+
}
|
|
51
|
+
const dir = getLocationDir(series, location.slug);
|
|
52
|
+
await mkdir(dir, { recursive: true });
|
|
53
|
+
const model = options.model ?? location.referenceModel ?? DEFAULT_IMAGE_GENERATION_MODEL;
|
|
54
|
+
const cfgScale = options.cfgScale ?? 10;
|
|
55
|
+
const aspect = series.storyboardAspectRatio ?? '16:9';
|
|
56
|
+
const aestheticStr = buildAestheticString(series.aesthetic);
|
|
57
|
+
const seed = location.seed;
|
|
58
|
+
const generated = [];
|
|
59
|
+
const skipped = [];
|
|
60
|
+
for (const angle of LOCATION_ANGLES) {
|
|
61
|
+
const imgPath = join(dir, `${angle}.png`);
|
|
62
|
+
if (existsSync(imgPath) && !options.force) {
|
|
63
|
+
skipped.push(imgPath);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
// Archive existing when forcing (asset-safety: never destructive).
|
|
67
|
+
if (existsSync(imgPath) && options.force) {
|
|
68
|
+
const archive = imgPath.replace(/\.png$/, `-force-archive-${Date.now()}.png`);
|
|
69
|
+
await rename(imgPath, archive);
|
|
70
|
+
}
|
|
71
|
+
// Front-load STYLE (rule 11) so the environment holds the series look.
|
|
72
|
+
const promptParts = [
|
|
73
|
+
`STYLE: ${aestheticStr}.`,
|
|
74
|
+
`${ANGLE_PROMPTS[angle]}.`,
|
|
75
|
+
`${location.description}.`,
|
|
76
|
+
location.lightingNotes ? `Lighting: ${location.lightingNotes}.` : '',
|
|
77
|
+
'Empty environment, no people present, no human figures, uninhabited scene.',
|
|
78
|
+
`STYLE REMINDER: ${aestheticStr}.`,
|
|
79
|
+
].filter(Boolean);
|
|
80
|
+
const prompt = promptParts.join(' ');
|
|
81
|
+
const negativePrompt = [
|
|
82
|
+
'people', 'person', 'human', 'figure', 'silhouette', 'crowd',
|
|
83
|
+
'deformed', 'blurry', 'low quality', 'watermark', 'text', 'signature',
|
|
84
|
+
'comic panels', 'panel borders', 'multiple frames',
|
|
85
|
+
].join(', ');
|
|
86
|
+
try {
|
|
87
|
+
const response = await generateImage(client, {
|
|
88
|
+
model,
|
|
89
|
+
prompt,
|
|
90
|
+
negative_prompt: negativePrompt,
|
|
91
|
+
resolution: '1K',
|
|
92
|
+
aspect_ratio: aspect,
|
|
93
|
+
steps: 30,
|
|
94
|
+
cfg_scale: cfgScale,
|
|
95
|
+
seed,
|
|
96
|
+
safe_mode: false,
|
|
97
|
+
hide_watermark: true,
|
|
98
|
+
});
|
|
99
|
+
if (!response.images?.[0]) {
|
|
100
|
+
console.warn(` ${angle}: no image returned`);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const imgBuffer = Buffer.from(response.images[0].b64_json, 'base64');
|
|
104
|
+
const finalPath = await writeImageBytesSmart(imgBuffer, imgPath);
|
|
105
|
+
console.log(` ${angle}: saved -> ${basename(finalPath)}`);
|
|
106
|
+
const returnedSeed = response.images[0].seed;
|
|
107
|
+
await writeFile(join(dir, `${angle}.prompt.json`), JSON.stringify({
|
|
108
|
+
location: location.name,
|
|
109
|
+
slug: location.slug,
|
|
110
|
+
angle,
|
|
111
|
+
model,
|
|
112
|
+
prompt,
|
|
113
|
+
negative_prompt: negativePrompt,
|
|
114
|
+
cfg_scale: cfgScale,
|
|
115
|
+
aspect_ratio: aspect,
|
|
116
|
+
resolution: '1K',
|
|
117
|
+
seed,
|
|
118
|
+
returnedSeed,
|
|
119
|
+
generatedAt: new Date().toISOString(),
|
|
120
|
+
}, null, 2), 'utf-8');
|
|
121
|
+
// Faceless by design → provenance hasFace:false so the Seedance
|
|
122
|
+
// pre-flight gate (which checks sceneImagePaths + referenceImagePaths)
|
|
123
|
+
// passes without laundering.
|
|
124
|
+
await appendRecipePass(finalPath, {
|
|
125
|
+
kind: 'generate',
|
|
126
|
+
role: 'content',
|
|
127
|
+
model,
|
|
128
|
+
label: `location reference (${location.name}, ${angle})`,
|
|
129
|
+
prompt,
|
|
130
|
+
negativePrompt,
|
|
131
|
+
seed,
|
|
132
|
+
cfgScale,
|
|
133
|
+
aspectRatio: aspect,
|
|
134
|
+
resolution: '1K',
|
|
135
|
+
}, { provenance: 'generate', hasFace: false });
|
|
136
|
+
generated.push(finalPath);
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
console.warn(` ${angle}: failed - ${err}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { generated, skipped };
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=location-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"location-generator.js","sourceRoot":"","sources":["../../src/mini-drama/location-generator.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,gCAAgC;AAChC,EAAE;AACF,kEAAkE;AAClE,6EAA6E;AAC7E,4EAA4E;AAC5E,iEAAiE;AACjE,gEAAgE;AAChE,EAAE;AACF,uEAAuE;AACvE,+EAA+E;AAC/E,8EAA8E;AAC9E,8EAA8E;AAC9E,0DAA0D;AAC1D,8EAA8E;AAE9E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,8BAA8B,EAAE,MAAM,oBAAoB,CAAC;AAGpE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAU,CAAC;AAGrE,MAAM,aAAa,GAAkC;IACnD,IAAI,EAAE,gGAAgG;IACtG,MAAM,EAAE,+FAA+F;IACvG,MAAM,EAAE,yFAAyF;CAClG,CAAC;AAEF,SAAS,oBAAoB,CAAC,SAA2B;IACvD,OAAO;QACL,SAAS,CAAC,KAAK;QACf,SAAS,CAAC,OAAO;QACjB,SAAS,CAAC,QAAQ;QAClB,SAAS,CAAC,mBAAmB;QAC7B,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,SAAS,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE;KAC5D;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAWD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,MAAoB,EACpB,MAAmB,EACnB,QAAkB,EAClB,UAA6C,EAAE;IAE/C,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;IAClD,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,QAAQ,CAAC,cAAc,IAAI,8BAA8B,CAAC;IACzF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,MAAM,CAAC,qBAAqB,IAAI,MAAM,CAAC;IACtD,MAAM,YAAY,GAAG,oBAAoB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;IAE3B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,MAAM,CAAC,CAAC;QAC1C,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC1C,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,mEAAmE;QACnE,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,kBAAkB,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC9E,MAAM,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACjC,CAAC;QAED,uEAAuE;QACvE,MAAM,WAAW,GAAG;YAClB,UAAU,YAAY,GAAG;YACzB,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG;YAC1B,GAAG,QAAQ,CAAC,WAAW,GAAG;YAC1B,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,QAAQ,CAAC,aAAa,GAAG,CAAC,CAAC,CAAC,EAAE;YACpE,4EAA4E;YAC5E,mBAAmB,YAAY,GAAG;SACnC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAClB,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,cAAc,GAAG;YACrB,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO;YAC5D,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW;YACrE,cAAc,EAAE,eAAe,EAAE,iBAAiB;SACnD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE;gBAC3C,KAAK;gBACL,MAAM;gBACN,eAAe,EAAE,cAAc;gBAC/B,UAAU,EAAE,IAAI;gBAChB,YAAY,EAAE,MAAM;gBACpB,KAAK,EAAE,EAAE;gBACT,SAAS,EAAE,QAAQ;gBACnB,IAAI;gBACJ,SAAS,EAAE,KAAK;gBAChB,cAAc,EAAE,IAAI;aACrB,CAAC,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,qBAAqB,CAAC,CAAC;gBAC9C,SAAS;YACX,CAAC;YACD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACrE,MAAM,SAAS,GAAG,MAAM,oBAAoB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YACjE,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,cAAc,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAE3D,MAAM,YAAY,GAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAuB,CAAC,IAAI,CAAC;YACpE,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,cAAc,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;gBAChE,QAAQ,EAAE,QAAQ,CAAC,IAAI;gBACvB,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,KAAK;gBACL,KAAK;gBACL,MAAM;gBACN,eAAe,EAAE,cAAc;gBAC/B,SAAS,EAAE,QAAQ;gBACnB,YAAY,EAAE,MAAM;gBACpB,UAAU,EAAE,IAAI;gBAChB,IAAI;gBACJ,YAAY;gBACZ,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACtC,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YAEtB,gEAAgE;YAChE,uEAAuE;YACvE,6BAA6B;YAC7B,MAAM,gBAAgB,CAAC,SAAS,EAAE;gBAChC,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,SAAS;gBACf,KAAK;gBACL,KAAK,EAAE,uBAAuB,QAAQ,CAAC,IAAI,KAAK,KAAK,GAAG;gBACxD,MAAM;gBACN,cAAc;gBACd,IAAI;gBACJ,QAAQ;gBACR,WAAW,EAAE,MAAM;gBACnB,UAAU,EAAE,IAAI;aACjB,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAE/C,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,KAAK,KAAK,cAAc,GAAG,EAAE,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { MusicCueSpec, ShotScript } from '../series/types.js';
|
|
2
|
+
/** A cue annotated with its resolved timeline window. */
|
|
3
|
+
export interface ResolvedMusicCue {
|
|
4
|
+
spec: MusicCueSpec;
|
|
5
|
+
/** Source audio file, after generation / passthrough. */
|
|
6
|
+
audioPath: string;
|
|
7
|
+
startSec: number;
|
|
8
|
+
endSec: number;
|
|
9
|
+
}
|
|
10
|
+
export interface PlacementMap {
|
|
11
|
+
/** Shot id (string, zero-padded for numeric shots like "003" / "003b"). */
|
|
12
|
+
[shotId: string]: {
|
|
13
|
+
startSec: number;
|
|
14
|
+
endSec: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** Normalize a shot id (number or string) to a string key. */
|
|
18
|
+
export declare function shotIdKey(id: number | string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a cue's timeline window from the placement map.
|
|
21
|
+
* Returns null when the start or end shot can't be found — callers should
|
|
22
|
+
* warn and skip the cue rather than emit a misaligned cue.
|
|
23
|
+
*/
|
|
24
|
+
export declare function resolveCueWindow(cue: MusicCueSpec, placementMap: PlacementMap): {
|
|
25
|
+
startSec: number;
|
|
26
|
+
endSec: number;
|
|
27
|
+
} | null;
|
|
28
|
+
/**
|
|
29
|
+
* Assemble a list of resolved cues into a single MP3 track with crossfades.
|
|
30
|
+
*
|
|
31
|
+
* For each cue:
|
|
32
|
+
* - trim/pad to the resolved window length,
|
|
33
|
+
* - apply gain and fade-in / fade-out,
|
|
34
|
+
* - acrossfade with the previous track at the trailing fade point.
|
|
35
|
+
*
|
|
36
|
+
* The output sample rate is fixed at 48000 Hz / stereo for compatibility
|
|
37
|
+
* with the assembler's final aac encode.
|
|
38
|
+
*/
|
|
39
|
+
export declare function renderMusicCuesTrack(opts: {
|
|
40
|
+
cues: ResolvedMusicCue[];
|
|
41
|
+
outputPath: string;
|
|
42
|
+
totalDurationSec: number;
|
|
43
|
+
/**
|
|
44
|
+
* Placement map used to resolve `gainStops[].atShot`. Optional — when
|
|
45
|
+
* omitted, gain stops are skipped (cues still honour the base `gain`).
|
|
46
|
+
*/
|
|
47
|
+
placementMap?: PlacementMap;
|
|
48
|
+
}): Promise<string>;
|
|
49
|
+
/**
|
|
50
|
+
* Build a single ffmpeg `volume=` expression that ramps gain through a cue's
|
|
51
|
+
* `gainStops[]`. Stops are ordered along the timeline and produce a smooth
|
|
52
|
+
* piecewise-linear curve.
|
|
53
|
+
*
|
|
54
|
+
* The expression evaluates `t` (timeline seconds) and returns a linear gain
|
|
55
|
+
* multiplier. Callers should pass the result with `volume=<expr>:eval=frame`.
|
|
56
|
+
*
|
|
57
|
+
* Returns null when the cue has no stops or none of them resolve to the
|
|
58
|
+
* placement map.
|
|
59
|
+
*/
|
|
60
|
+
export declare function buildGainStopsExpr(cue: ResolvedMusicCue, placementMap: PlacementMap): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* derive a per-shot volume curve for music automation.
|
|
63
|
+
*
|
|
64
|
+
* Combines `shot.musicHold` with the containing cue's `musicHold` and
|
|
65
|
+
* returns an ffmpeg `volume=` expression suitable for layering over the
|
|
66
|
+
* already-rendered cues track. Returns `null` when no automation is needed
|
|
67
|
+
* (everything is sustain).
|
|
68
|
+
*
|
|
69
|
+
* The expression evaluates `t` (timeline seconds) and produces a multiplier
|
|
70
|
+
* in [0, 4] — 1.0 is unity, sub-1 ducks, super-1 swells.
|
|
71
|
+
*
|
|
72
|
+
* stinger: 0.4s pulse +6 dB at the start of the shot, return to 1.0
|
|
73
|
+
* swell: linear ramp from 1.0 to 1.58 (+4 dB) across the shot
|
|
74
|
+
* drop: constant 0.001 (≈ -60 dB) for the shot's duration
|
|
75
|
+
* sustain: no change
|
|
76
|
+
*/
|
|
77
|
+
export declare function buildMusicHoldExpr(shots: ShotScript[], placementMap: PlacementMap): string | null;
|
|
78
|
+
/**
|
|
79
|
+
* Apply a `volume=` expression to an existing music track and emit a new file.
|
|
80
|
+
* Use this AFTER `renderMusicCuesTrack` to layer `musicHold` automation
|
|
81
|
+
* without re-rendering the full filter graph.
|
|
82
|
+
*/
|
|
83
|
+
export declare function applyMusicHoldAutomation(opts: {
|
|
84
|
+
inputPath: string;
|
|
85
|
+
outputPath: string;
|
|
86
|
+
volumeExpr: string;
|
|
87
|
+
}): Promise<string>;
|
|
88
|
+
/**
|
|
89
|
+
* Convenience: convert a flat list of cue specs into resolved cues by
|
|
90
|
+
* looking up each in the placement map. Cues whose start or end shot
|
|
91
|
+
* cannot be resolved are skipped (with a console.warn) — they were
|
|
92
|
+
* scripted but the placement map doesn't have the shot yet, e.g. because
|
|
93
|
+
* the shot is out of range or was removed.
|
|
94
|
+
*/
|
|
95
|
+
export declare function resolveMusicCues(specs: MusicCueSpec[], placementMap: PlacementMap, audioPathFor: (spec: MusicCueSpec) => string | undefined): ResolvedMusicCue[];
|
|
96
|
+
//# sourceMappingURL=music-cues.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"music-cues.d.ts","sourceRoot":"","sources":["../../src/mini-drama/music-cues.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQnE,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,CAAC;IACnB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,2EAA2E;IAC3E,CAAC,MAAM,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACxD;AAED,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAMrD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,YAAY,EACjB,YAAY,EAAE,YAAY,GACzB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAO7C;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,IAAI,EAAE,gBAAgB,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,GAAG,OAAO,CAAC,MAAM,CAAC,CAmIlB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,gBAAgB,EACrB,YAAY,EAAE,YAAY,GACzB,MAAM,GAAG,IAAI,CA0Cf;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,UAAU,EAAE,EACnB,YAAY,EAAE,YAAY,GACzB,MAAM,GAAG,IAAI,CA4Bf;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CAclB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,YAAY,EAAE,EACrB,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,GAAG,SAAS,GACvD,gBAAgB,EAAE,CAgBpB"}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Per-act music cues with ffmpeg crossfades.
|
|
3
|
+
//
|
|
4
|
+
// Replaces the assembler's single-static-bed model with an ordered list of
|
|
5
|
+
// cues, each anchored to a shot id. Cues crossfade at their configured fade
|
|
6
|
+
// points so beats can change with the story: bed → ominous → bed → climactic.
|
|
7
|
+
//
|
|
8
|
+
// Per-shot musicHold (sustain / swell / drop / stinger) layers automation on
|
|
9
|
+
// top of the cue: volume ramps, sidechain ducks, transient stingers.
|
|
10
|
+
//
|
|
11
|
+
// This module is pure orchestration — it shells ffmpeg via execFile but does
|
|
12
|
+
// not know how to call Venice. Cue audio is either supplied via
|
|
13
|
+
// `cue.audioPath` or rendered separately and the path threaded in by the
|
|
14
|
+
// caller (see the music-cue reference scripts).
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
import { execFile } from 'node:child_process';
|
|
17
|
+
import { mkdir } from 'node:fs/promises';
|
|
18
|
+
import { existsSync } from 'node:fs';
|
|
19
|
+
import { dirname } from 'node:path';
|
|
20
|
+
import { promisify } from 'node:util';
|
|
21
|
+
const execFileAsync = promisify(execFile);
|
|
22
|
+
const DEFAULT_GAIN_DB = -22;
|
|
23
|
+
const DEFAULT_FADE_IN = 1.0;
|
|
24
|
+
const DEFAULT_FADE_OUT = 1.5;
|
|
25
|
+
/** Normalize a shot id (number or string) to a string key. */
|
|
26
|
+
export function shotIdKey(id) {
|
|
27
|
+
if (typeof id === 'number')
|
|
28
|
+
return String(id).padStart(3, '0');
|
|
29
|
+
// Suffixed forms like "3b" -> "003b". Suffix letters preserved as-is.
|
|
30
|
+
const match = id.match(/^(\d+)([a-zA-Z]*)$/);
|
|
31
|
+
if (match)
|
|
32
|
+
return String(match[1]).padStart(3, '0') + match[2];
|
|
33
|
+
return id;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a cue's timeline window from the placement map.
|
|
37
|
+
* Returns null when the start or end shot can't be found — callers should
|
|
38
|
+
* warn and skip the cue rather than emit a misaligned cue.
|
|
39
|
+
*/
|
|
40
|
+
export function resolveCueWindow(cue, placementMap) {
|
|
41
|
+
const startKey = shotIdKey(cue.startShot);
|
|
42
|
+
const endKey = shotIdKey(cue.endShot);
|
|
43
|
+
const start = placementMap[startKey];
|
|
44
|
+
const end = placementMap[endKey];
|
|
45
|
+
if (!start || !end)
|
|
46
|
+
return null;
|
|
47
|
+
return { startSec: start.startSec, endSec: end.endSec };
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Assemble a list of resolved cues into a single MP3 track with crossfades.
|
|
51
|
+
*
|
|
52
|
+
* For each cue:
|
|
53
|
+
* - trim/pad to the resolved window length,
|
|
54
|
+
* - apply gain and fade-in / fade-out,
|
|
55
|
+
* - acrossfade with the previous track at the trailing fade point.
|
|
56
|
+
*
|
|
57
|
+
* The output sample rate is fixed at 48000 Hz / stereo for compatibility
|
|
58
|
+
* with the assembler's final aac encode.
|
|
59
|
+
*/
|
|
60
|
+
export async function renderMusicCuesTrack(opts) {
|
|
61
|
+
if (opts.cues.length === 0) {
|
|
62
|
+
throw new Error('renderMusicCuesTrack: at least one cue is required');
|
|
63
|
+
}
|
|
64
|
+
await mkdir(dirname(opts.outputPath), { recursive: true });
|
|
65
|
+
// For a single cue, just gain + fade + write.
|
|
66
|
+
if (opts.cues.length === 1) {
|
|
67
|
+
const cue = opts.cues[0];
|
|
68
|
+
const dur = cue.endSec - cue.startSec;
|
|
69
|
+
const gain = cue.spec.gain ?? DEFAULT_GAIN_DB;
|
|
70
|
+
const fadeIn = cue.spec.fadeIn ?? DEFAULT_FADE_IN;
|
|
71
|
+
const fadeOut = cue.spec.fadeOut ?? DEFAULT_FADE_OUT;
|
|
72
|
+
// gainStops[] runs in cue-local time, so build the expression then offset
|
|
73
|
+
// its `t` by the cue's start. Easier: render the base bed without
|
|
74
|
+
// gainStops, then apply the expression on the final track (which is
|
|
75
|
+
// already in timeline time).
|
|
76
|
+
const filter = [
|
|
77
|
+
`volume=${gain}dB`,
|
|
78
|
+
`afade=t=in:st=0:d=${fadeIn}`,
|
|
79
|
+
`afade=t=out:st=${Math.max(0, dur - fadeOut)}:d=${fadeOut}`,
|
|
80
|
+
].join(',');
|
|
81
|
+
await execFileAsync('ffmpeg', [
|
|
82
|
+
'-y',
|
|
83
|
+
'-i', cue.audioPath,
|
|
84
|
+
'-af', filter,
|
|
85
|
+
'-t', String(dur),
|
|
86
|
+
'-ar', '48000',
|
|
87
|
+
'-ac', '2',
|
|
88
|
+
opts.outputPath,
|
|
89
|
+
]);
|
|
90
|
+
// gainStops: the expression evaluates against timeline t. By convention
|
|
91
|
+
// cue 1 begins at timeline t=0 (the music bed aligns to the first shot),
|
|
92
|
+
// so the rendered mp3's local time axis matches the timeline. For
|
|
93
|
+
// single-cue renderings that begin later, callers should pre-pad the
|
|
94
|
+
// bed (out of scope here).
|
|
95
|
+
if (opts.placementMap) {
|
|
96
|
+
const stopsExpr = buildGainStopsExpr(cue, opts.placementMap);
|
|
97
|
+
if (stopsExpr) {
|
|
98
|
+
const tmp = opts.outputPath.replace(/\.mp3$/, '-gainstops.mp3');
|
|
99
|
+
await execFileAsync('ffmpeg', [
|
|
100
|
+
'-y',
|
|
101
|
+
'-i', opts.outputPath,
|
|
102
|
+
'-af', `volume='${stopsExpr}':eval=frame`,
|
|
103
|
+
'-ar', '48000',
|
|
104
|
+
'-ac', '2',
|
|
105
|
+
tmp,
|
|
106
|
+
]);
|
|
107
|
+
const { rename } = await import('node:fs/promises');
|
|
108
|
+
await rename(tmp, opts.outputPath);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return opts.outputPath;
|
|
112
|
+
}
|
|
113
|
+
// Multi-cue path: build a concat-with-crossfade filter graph.
|
|
114
|
+
const inputs = [];
|
|
115
|
+
for (const cue of opts.cues) {
|
|
116
|
+
inputs.push('-i', cue.audioPath);
|
|
117
|
+
}
|
|
118
|
+
// Build per-input filter chains, then chain acrossfade between them.
|
|
119
|
+
const filterParts = [];
|
|
120
|
+
for (let i = 0; i < opts.cues.length; i++) {
|
|
121
|
+
const cue = opts.cues[i];
|
|
122
|
+
const dur = cue.endSec - cue.startSec;
|
|
123
|
+
const gain = cue.spec.gain ?? DEFAULT_GAIN_DB;
|
|
124
|
+
const fadeIn = cue.spec.fadeIn ?? DEFAULT_FADE_IN;
|
|
125
|
+
// Trim/pad to window length, apply gain. Inner fade-in only — the
|
|
126
|
+
// crossfade handles outgoing edges. The very first cue gets a fade-in,
|
|
127
|
+
// the very last cue gets a fade-out.
|
|
128
|
+
const chain = [`atrim=0:${dur}`, `asetpts=N/SR/TB`, `volume=${gain}dB`];
|
|
129
|
+
if (i === 0)
|
|
130
|
+
chain.push(`afade=t=in:st=0:d=${fadeIn}`);
|
|
131
|
+
if (i === opts.cues.length - 1) {
|
|
132
|
+
const fadeOut = cue.spec.fadeOut ?? DEFAULT_FADE_OUT;
|
|
133
|
+
chain.push(`afade=t=out:st=${Math.max(0, dur - fadeOut)}:d=${fadeOut}`);
|
|
134
|
+
}
|
|
135
|
+
filterParts.push(`[${i}:a]${chain.join(',')}[a${i}]`);
|
|
136
|
+
}
|
|
137
|
+
// Chain acrossfade: [a0][a1]acrossfade=d=X[ax1]; [ax1][a2]acrossfade=d=Y[ax2]; ...
|
|
138
|
+
let prevLabel = '[a0]';
|
|
139
|
+
for (let i = 1; i < opts.cues.length; i++) {
|
|
140
|
+
// Crossfade duration is the min of the trailing fadeOut on the previous
|
|
141
|
+
// cue and the leading fadeIn on the next cue — this is the overlap region
|
|
142
|
+
// both cues already attenuate.
|
|
143
|
+
const prev = opts.cues[i - 1].spec;
|
|
144
|
+
const next = opts.cues[i].spec;
|
|
145
|
+
const xfade = Math.min(prev.fadeOut ?? DEFAULT_FADE_OUT, next.fadeIn ?? DEFAULT_FADE_IN);
|
|
146
|
+
const outLabel = i === opts.cues.length - 1 ? '[aout]' : `[ax${i}]`;
|
|
147
|
+
filterParts.push(`${prevLabel}[a${i}]acrossfade=d=${xfade.toFixed(3)}:c1=tri:c2=tri${outLabel}`);
|
|
148
|
+
prevLabel = outLabel;
|
|
149
|
+
}
|
|
150
|
+
await execFileAsync('ffmpeg', [
|
|
151
|
+
'-y',
|
|
152
|
+
...inputs,
|
|
153
|
+
'-filter_complex', filterParts.join(';'),
|
|
154
|
+
'-map', '[aout]',
|
|
155
|
+
'-ar', '48000',
|
|
156
|
+
'-ac', '2',
|
|
157
|
+
opts.outputPath,
|
|
158
|
+
]);
|
|
159
|
+
// Apply per-cue gainStops on the assembled bed. The expression evaluates
|
|
160
|
+
// against timeline t, which matches the assembled mp3's local time axis as
|
|
161
|
+
// long as cue 1 starts at timeline t=0 (the standard layout).
|
|
162
|
+
if (opts.placementMap) {
|
|
163
|
+
const exprs = [];
|
|
164
|
+
for (const cue of opts.cues) {
|
|
165
|
+
const e = buildGainStopsExpr(cue, opts.placementMap);
|
|
166
|
+
if (e)
|
|
167
|
+
exprs.push(e);
|
|
168
|
+
}
|
|
169
|
+
if (exprs.length > 0) {
|
|
170
|
+
const filters = exprs.map(e => `volume='${e}':eval=frame`).join(',');
|
|
171
|
+
const tmp = opts.outputPath.replace(/\.mp3$/, '-gainstops.mp3');
|
|
172
|
+
await execFileAsync('ffmpeg', [
|
|
173
|
+
'-y',
|
|
174
|
+
'-i', opts.outputPath,
|
|
175
|
+
'-af', filters,
|
|
176
|
+
'-ar', '48000',
|
|
177
|
+
'-ac', '2',
|
|
178
|
+
tmp,
|
|
179
|
+
]);
|
|
180
|
+
const { rename } = await import('node:fs/promises');
|
|
181
|
+
await rename(tmp, opts.outputPath);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return opts.outputPath;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Build a single ffmpeg `volume=` expression that ramps gain through a cue's
|
|
188
|
+
* `gainStops[]`. Stops are ordered along the timeline and produce a smooth
|
|
189
|
+
* piecewise-linear curve.
|
|
190
|
+
*
|
|
191
|
+
* The expression evaluates `t` (timeline seconds) and returns a linear gain
|
|
192
|
+
* multiplier. Callers should pass the result with `volume=<expr>:eval=frame`.
|
|
193
|
+
*
|
|
194
|
+
* Returns null when the cue has no stops or none of them resolve to the
|
|
195
|
+
* placement map.
|
|
196
|
+
*/
|
|
197
|
+
export function buildGainStopsExpr(cue, placementMap) {
|
|
198
|
+
const stops = cue.spec.gainStops;
|
|
199
|
+
if (!stops || stops.length === 0)
|
|
200
|
+
return null;
|
|
201
|
+
const baseDb = cue.spec.gain ?? DEFAULT_GAIN_DB;
|
|
202
|
+
const baseGain = Math.pow(10, baseDb / 20);
|
|
203
|
+
const resolved = [];
|
|
204
|
+
for (const s of stops) {
|
|
205
|
+
const placement = placementMap[shotIdKey(s.atShot)];
|
|
206
|
+
if (!placement) {
|
|
207
|
+
console.warn(` music-cue: gain stop atShot=${s.atShot} not in placement map; skipping`);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (placement.startSec < cue.startSec || placement.startSec > cue.endSec) {
|
|
211
|
+
console.warn(` music-cue: gain stop atShot=${s.atShot} is outside cue window; skipping`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
resolved.push({
|
|
215
|
+
t: placement.startSec,
|
|
216
|
+
gain: Math.pow(10, s.gainDb / 20),
|
|
217
|
+
rampSec: s.rampSec ?? 2.0,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
if (resolved.length === 0)
|
|
221
|
+
return null;
|
|
222
|
+
resolved.sort((a, b) => a.t - b.t);
|
|
223
|
+
// Build a nested piecewise expression:
|
|
224
|
+
// t < t1 - r1/2 -> baseGain
|
|
225
|
+
// t1-r1/2 .. t1+r1/2 -> linear ramp baseGain -> g1
|
|
226
|
+
// t1+r1/2 .. t2-r2/2 -> g1
|
|
227
|
+
// t2-r2/2 .. t2+r2/2 -> linear ramp g1 -> g2
|
|
228
|
+
// ... -> gN
|
|
229
|
+
let prevGain = baseGain;
|
|
230
|
+
let expr = `${baseGain.toFixed(6)}`;
|
|
231
|
+
for (const s of resolved) {
|
|
232
|
+
const rampStart = (s.t - s.rampSec / 2).toFixed(3);
|
|
233
|
+
const rampEnd = (s.t + s.rampSec / 2).toFixed(3);
|
|
234
|
+
const ramp = `(${prevGain.toFixed(6)}+(${s.gain.toFixed(6)}-${prevGain.toFixed(6)})*(t-${rampStart})/${s.rampSec.toFixed(3)})`;
|
|
235
|
+
expr = `if(lt(t,${rampStart}),${expr},if(lt(t,${rampEnd}),${ramp},${s.gain.toFixed(6)}))`;
|
|
236
|
+
prevGain = s.gain;
|
|
237
|
+
}
|
|
238
|
+
return expr;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* derive a per-shot volume curve for music automation.
|
|
242
|
+
*
|
|
243
|
+
* Combines `shot.musicHold` with the containing cue's `musicHold` and
|
|
244
|
+
* returns an ffmpeg `volume=` expression suitable for layering over the
|
|
245
|
+
* already-rendered cues track. Returns `null` when no automation is needed
|
|
246
|
+
* (everything is sustain).
|
|
247
|
+
*
|
|
248
|
+
* The expression evaluates `t` (timeline seconds) and produces a multiplier
|
|
249
|
+
* in [0, 4] — 1.0 is unity, sub-1 ducks, super-1 swells.
|
|
250
|
+
*
|
|
251
|
+
* stinger: 0.4s pulse +6 dB at the start of the shot, return to 1.0
|
|
252
|
+
* swell: linear ramp from 1.0 to 1.58 (+4 dB) across the shot
|
|
253
|
+
* drop: constant 0.001 (≈ -60 dB) for the shot's duration
|
|
254
|
+
* sustain: no change
|
|
255
|
+
*/
|
|
256
|
+
export function buildMusicHoldExpr(shots, placementMap) {
|
|
257
|
+
const pieces = [];
|
|
258
|
+
for (const shot of shots) {
|
|
259
|
+
const hold = shot.musicHold;
|
|
260
|
+
if (!hold || hold === 'sustain')
|
|
261
|
+
continue;
|
|
262
|
+
const placement = placementMap[shotIdKey(shot.shotNumber)];
|
|
263
|
+
if (!placement)
|
|
264
|
+
continue;
|
|
265
|
+
const { startSec, endSec } = placement;
|
|
266
|
+
if (hold === 'stinger') {
|
|
267
|
+
pieces.push(`if(between(t,${startSec.toFixed(3)},${(startSec + 0.4).toFixed(3)}),2.0,`);
|
|
268
|
+
pieces.push(')'); // close the if — placeholder; we wrap below.
|
|
269
|
+
}
|
|
270
|
+
else if (hold === 'swell') {
|
|
271
|
+
// 1.0 -> 1.58 across the shot
|
|
272
|
+
pieces.push(`if(between(t,${startSec.toFixed(3)},${endSec.toFixed(3)}),` +
|
|
273
|
+
`1.0+(0.58*(t-${startSec.toFixed(3)})/${(endSec - startSec).toFixed(3)}),`);
|
|
274
|
+
pieces.push(')');
|
|
275
|
+
}
|
|
276
|
+
else if (hold === 'drop') {
|
|
277
|
+
pieces.push(`if(between(t,${startSec.toFixed(3)},${endSec.toFixed(3)}),0.001,`);
|
|
278
|
+
pieces.push(')');
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (pieces.length === 0)
|
|
282
|
+
return null;
|
|
283
|
+
// Nest the if-expressions with `1` (sustain) as the innermost else.
|
|
284
|
+
const opens = pieces.filter(p => p !== ')');
|
|
285
|
+
const closes = pieces.filter(p => p === ')').length;
|
|
286
|
+
return opens.join('') + '1' + ')'.repeat(closes);
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Apply a `volume=` expression to an existing music track and emit a new file.
|
|
290
|
+
* Use this AFTER `renderMusicCuesTrack` to layer `musicHold` automation
|
|
291
|
+
* without re-rendering the full filter graph.
|
|
292
|
+
*/
|
|
293
|
+
export async function applyMusicHoldAutomation(opts) {
|
|
294
|
+
if (!existsSync(opts.inputPath)) {
|
|
295
|
+
throw new Error(`applyMusicHoldAutomation: input not found at ${opts.inputPath}`);
|
|
296
|
+
}
|
|
297
|
+
await mkdir(dirname(opts.outputPath), { recursive: true });
|
|
298
|
+
await execFileAsync('ffmpeg', [
|
|
299
|
+
'-y',
|
|
300
|
+
'-i', opts.inputPath,
|
|
301
|
+
'-af', `volume=${opts.volumeExpr}:eval=frame`,
|
|
302
|
+
'-ar', '48000',
|
|
303
|
+
'-ac', '2',
|
|
304
|
+
opts.outputPath,
|
|
305
|
+
]);
|
|
306
|
+
return opts.outputPath;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Convenience: convert a flat list of cue specs into resolved cues by
|
|
310
|
+
* looking up each in the placement map. Cues whose start or end shot
|
|
311
|
+
* cannot be resolved are skipped (with a console.warn) — they were
|
|
312
|
+
* scripted but the placement map doesn't have the shot yet, e.g. because
|
|
313
|
+
* the shot is out of range or was removed.
|
|
314
|
+
*/
|
|
315
|
+
export function resolveMusicCues(specs, placementMap, audioPathFor) {
|
|
316
|
+
const out = [];
|
|
317
|
+
for (const spec of specs) {
|
|
318
|
+
const window = resolveCueWindow(spec, placementMap);
|
|
319
|
+
if (!window) {
|
|
320
|
+
console.warn(` music-cue: skipping cue ${shotIdKey(spec.startShot)}->${shotIdKey(spec.endShot)} — shot ids not in placement map`);
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const audioPath = spec.audioPath ?? audioPathFor(spec);
|
|
324
|
+
if (!audioPath || !existsSync(audioPath)) {
|
|
325
|
+
console.warn(` music-cue: skipping cue ${shotIdKey(spec.startShot)}->${shotIdKey(spec.endShot)} — audio file missing`);
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
out.push({ spec, audioPath, startSec: window.startSec, endSec: window.endSec });
|
|
329
|
+
}
|
|
330
|
+
return out;
|
|
331
|
+
}
|
|
332
|
+
//# sourceMappingURL=music-cues.js.map
|