@bendyline/squisq-video-react 2.4.20 → 2.4.22

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.
@@ -0,0 +1,157 @@
1
+ import {
2
+ LOSSY_FORMATS,
3
+ assertOpen,
4
+ blockFrames,
5
+ createSerialQueue
6
+ } from "./chunk-2W6JQSIY.js";
7
+
8
+ // src/audioFile/wavStream.ts
9
+ var HEADER_BYTES = 44;
10
+ var BYTES_PER_SAMPLE = 2;
11
+ var MAX_WAV_DATA_BYTES = 4294967295 - 36;
12
+ var DEFAULT_CHUNK_BYTES = 1 << 20;
13
+ function wavHeader(sampleRate, channels, dataBytes) {
14
+ const header = new Uint8Array(HEADER_BYTES);
15
+ const view = new DataView(header.buffer);
16
+ const ascii = (offset, text) => {
17
+ for (let i = 0; i < text.length; i++) view.setUint8(offset + i, text.charCodeAt(i));
18
+ };
19
+ const blockAlign = channels * BYTES_PER_SAMPLE;
20
+ ascii(0, "RIFF");
21
+ view.setUint32(4, 36 + dataBytes, true);
22
+ ascii(8, "WAVE");
23
+ ascii(12, "fmt ");
24
+ view.setUint32(16, 16, true);
25
+ view.setUint16(20, 1, true);
26
+ view.setUint16(22, channels, true);
27
+ view.setUint32(24, sampleRate, true);
28
+ view.setUint32(28, sampleRate * blockAlign, true);
29
+ view.setUint16(32, blockAlign, true);
30
+ view.setUint16(34, BYTES_PER_SAMPLE * 8, true);
31
+ ascii(36, "data");
32
+ view.setUint32(40, dataBytes, true);
33
+ return header;
34
+ }
35
+ function toPcm16(sample) {
36
+ if (!(sample > -1)) return sample <= -1 ? -32768 : 0;
37
+ if (sample >= 1) return 32767;
38
+ return Math.round(sample < 0 ? sample * 32768 : sample * 32767);
39
+ }
40
+ function createWavStreamWriter(sampleRate, channels, options = {}) {
41
+ const blockAlign = channels * BYTES_PER_SAMPLE;
42
+ const chunkFrames = Math.max(
43
+ 1,
44
+ Math.floor((options.chunkBytes ?? DEFAULT_CHUNK_BYTES) / blockAlign)
45
+ );
46
+ const scratch = new ArrayBuffer(chunkFrames * blockAlign);
47
+ const view = new DataView(scratch);
48
+ const parts = [];
49
+ let pendingFrames = 0;
50
+ let dataBytes = 0;
51
+ let finished = false;
52
+ const flushScratch = () => {
53
+ if (pendingFrames === 0) return;
54
+ parts.push(new Blob([new Uint8Array(scratch, 0, pendingFrames * blockAlign)]));
55
+ pendingFrames = 0;
56
+ };
57
+ return {
58
+ get dataBytes() {
59
+ return dataBytes;
60
+ },
61
+ append(planar) {
62
+ if (finished) throw new Error("The WAV writer is already finished.");
63
+ const frames = planar[0]?.length ?? 0;
64
+ if (frames === 0) return;
65
+ if (dataBytes + frames * blockAlign > MAX_WAV_DATA_BYTES) {
66
+ throw new RangeError("WAV files cannot exceed 4 GiB; use a compressed format instead.");
67
+ }
68
+ for (let frame = 0; frame < frames; frame++) {
69
+ let offset = pendingFrames * blockAlign;
70
+ for (let c = 0; c < channels; c++) {
71
+ view.setInt16(offset, toPcm16(planar[c][frame]), true);
72
+ offset += BYTES_PER_SAMPLE;
73
+ }
74
+ pendingFrames += 1;
75
+ if (pendingFrames === chunkFrames) flushScratch();
76
+ }
77
+ dataBytes += frames * blockAlign;
78
+ },
79
+ finish() {
80
+ if (finished) throw new Error("The WAV writer is already finished.");
81
+ finished = true;
82
+ flushScratch();
83
+ const blob = new Blob([wavHeader(sampleRate, channels, dataBytes), ...parts], {
84
+ type: "audio/wav"
85
+ });
86
+ parts.length = 0;
87
+ return blob;
88
+ }
89
+ };
90
+ }
91
+
92
+ // src/audioFile/audioFileEncoder.ts
93
+ var lossyModule = null;
94
+ function loadLossyModule() {
95
+ lossyModule ?? (lossyModule = import("./lossyEncoder-EIXBAOLG.js"));
96
+ return lossyModule;
97
+ }
98
+ function validateOptions(options) {
99
+ if (options.format !== "wav" && !(options.format in LOSSY_FORMATS)) {
100
+ throw new RangeError(`Unknown audio file format: ${String(options.format)}`);
101
+ }
102
+ if (!Number.isInteger(options.sampleRate) || options.sampleRate < 3e3 || options.sampleRate > 768e3) {
103
+ throw new RangeError(`Unsupported sample rate: ${options.sampleRate}`);
104
+ }
105
+ if (options.channels !== 1 && options.channels !== 2) {
106
+ throw new RangeError(`Audio files support 1 or 2 channels (got ${String(options.channels)}).`);
107
+ }
108
+ if (options.bitrate !== void 0 && (!Number.isFinite(options.bitrate) || options.bitrate < 6e3 || options.bitrate > 512e3)) {
109
+ throw new RangeError(`Unsupported bitrate: ${options.bitrate}`);
110
+ }
111
+ }
112
+ async function supportedAudioFileFormats() {
113
+ const formats = [];
114
+ try {
115
+ const lossy = await loadLossyModule();
116
+ for (const info of [LOSSY_FORMATS.m4a, LOSSY_FORMATS["opus-webm"]]) {
117
+ if (await lossy.canEncodeLossyFormat(info)) formats.push(info.format);
118
+ }
119
+ } catch {
120
+ }
121
+ formats.push("wav");
122
+ return formats;
123
+ }
124
+ async function createAudioFileEncoder(options) {
125
+ validateOptions(options);
126
+ if (options.format === "wav") return createWavEncoder(options);
127
+ const lossy = await loadLossyModule();
128
+ return lossy.createLossyEncoder(options, LOSSY_FORMATS[options.format]);
129
+ }
130
+ function createWavEncoder(options) {
131
+ const writer = createWavStreamWriter(options.sampleRate, options.channels);
132
+ const serial = createSerialQueue();
133
+ let state = "open";
134
+ return {
135
+ format: "wav",
136
+ mimeType: "audio/wav",
137
+ extension: "wav",
138
+ append: (block) => serial(async () => {
139
+ assertOpen(state);
140
+ blockFrames(block, options.channels);
141
+ writer.append(block);
142
+ }),
143
+ finish: () => serial(async () => {
144
+ assertOpen(state);
145
+ state = "finished";
146
+ return writer.finish();
147
+ }),
148
+ cancel: async () => {
149
+ if (state === "open") state = "cancelled";
150
+ }
151
+ };
152
+ }
153
+
154
+ export {
155
+ supportedAudioFileFormats,
156
+ createAudioFileEncoder
157
+ };
@@ -450,6 +450,68 @@ async function muxAudioWithFfmpegWasm(videoMp4, wav, audioBitrate, loadConfig) {
450
450
  }
451
451
  }
452
452
 
453
+ // src/documentAudio.ts
454
+ import { computeAudioTimeline } from "@bendyline/squisq-video";
455
+ function documentAudioTimeline(doc, options = {}) {
456
+ const offset = options.offsetSec ?? 0;
457
+ return options.processedAudio ? computeAudioTimeline(doc, offset, { processedAudio: options.processedAudio }) : computeAudioTimeline(doc, offset);
458
+ }
459
+ async function loadAudioTimelineSources(timeline, readMedia, signal) {
460
+ const buffers = /* @__PURE__ */ new Map();
461
+ const missing = [];
462
+ for (const src of new Set(timeline.map((clip) => clip.src))) {
463
+ signal?.throwIfAborted();
464
+ const data = await readMedia(src);
465
+ if (data) buffers.set(src, data);
466
+ else missing.push(src);
467
+ }
468
+ signal?.throwIfAborted();
469
+ return { buffers, missing };
470
+ }
471
+ function audioTimelineEnd(timeline, minDurationSec = 0) {
472
+ const floor = Number.isFinite(minDurationSec) ? Math.max(0, minDurationSec) : 0;
473
+ return timeline.reduce((end, clip) => Math.max(end, clip.startSec + clip.durationSec), floor);
474
+ }
475
+ function mixAudioTimeline(timeline, buffers, minDurationSec, sampleRate = EXPORT_AUDIO_SAMPLE_RATE) {
476
+ return renderAudioTimeline(
477
+ timeline,
478
+ buffers,
479
+ audioTimelineEnd(timeline, minDurationSec),
480
+ sampleRate
481
+ );
482
+ }
483
+ async function renderDocumentAudio(doc, options) {
484
+ const { signal } = options;
485
+ signal?.throwIfAborted();
486
+ const timeline = documentAudioTimeline(
487
+ doc,
488
+ options.processedAudio ? { processedAudio: options.processedAudio } : {}
489
+ );
490
+ if (timeline.length === 0) return null;
491
+ const { buffers, missing } = await loadAudioTimelineSources(
492
+ timeline,
493
+ (src) => options.readMedia(src),
494
+ signal
495
+ );
496
+ try {
497
+ if (missing.length > 0 && (options.missingMedia ?? "error") === "error") {
498
+ throw new Error(`Audio files could not be loaded: ${missing.join(", ")}`);
499
+ }
500
+ const playable = timeline.filter((clip) => buffers.has(clip.src));
501
+ if (playable.length === 0) return null;
502
+ const mixed = await mixAudioTimeline(
503
+ playable,
504
+ buffers,
505
+ doc.duration,
506
+ options.sampleRate ?? EXPORT_AUDIO_SAMPLE_RATE
507
+ );
508
+ signal?.throwIfAborted();
509
+ return mixed;
510
+ } finally {
511
+ buffers.clear();
512
+ }
513
+ }
514
+
453
515
  export {
454
516
  supportsWebCodecs,
455
517
  supportsWebCodecsH264,
@@ -461,5 +523,9 @@ export {
461
523
  renderAudioTimeline,
462
524
  encodeAacTrack,
463
525
  audioBufferToWav,
464
- muxAudioWithFfmpegWasm
526
+ muxAudioWithFfmpegWasm,
527
+ documentAudioTimeline,
528
+ loadAudioTimelineSources,
529
+ mixAudioTimeline,
530
+ renderDocumentAudio
465
531
  };
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-3NJDHK62.js";
8
8
  import {
9
9
  useFrameCapture
10
- } from "./chunk-QJWEZRZS.js";
10
+ } from "./chunk-A52VG7RA.js";
11
11
 
12
12
  // src/CoverImageExportModal.tsx
13
13
  import { useCallback, useId, useRef, useState } from "react";
@@ -7,7 +7,7 @@ var inlineDenoiser = createRnnoiseDenoiserFactory(
7
7
  () => import("@shiguredo/rnnoise-wasm").then(({ Rnnoise }) => Rnnoise.load())
8
8
  );
9
9
  async function inlineEngine() {
10
- return import("./mediaEditEngine-ZLG7D3TB.js");
10
+ return import("./mediaEditEngine-JLZ4Z5BB.js");
11
11
  }
12
12
  function inlineOptions(options) {
13
13
  return { ...options, denoiser: options.denoiser ?? inlineDenoiser };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  useVideoExport
3
- } from "./chunk-MI4EJXTD.js";
3
+ } from "./chunk-47ODXCBA.js";
4
4
 
5
5
  // src/VideoExportModal.tsx
6
6
  import { useState, useCallback, useEffect, useId, useRef } from "react";
@@ -317,6 +317,7 @@ function VideoExportModal({
317
317
  ]);
318
318
  const [saving, setSaving] = useState(false);
319
319
  const [saveError, setSaveError] = useState(null);
320
+ const [savedOutput, setSavedOutput] = useState(null);
320
321
  const handleSave = useCallback(async () => {
321
322
  if (!downloadUrl || !outputBlob) return;
322
323
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
@@ -329,11 +330,12 @@ function VideoExportModal({
329
330
  document.body.appendChild(a);
330
331
  a.click();
331
332
  document.body.removeChild(a);
333
+ setSavedOutput(outputBlob);
332
334
  return;
333
335
  }
334
336
  setSaving(true);
335
337
  try {
336
- await saveOutput(outputBlob, filename);
338
+ if (await saveOutput(outputBlob, filename) !== false) setSavedOutput(outputBlob);
337
339
  } catch (caught) {
338
340
  setSaveError(caught instanceof Error ? caught.message : "The export could not be saved.");
339
341
  } finally {
@@ -349,10 +351,11 @@ function VideoExportModal({
349
351
  onClose();
350
352
  }, [state, cancelExport, resetExport, onClose]);
351
353
  const isExporting = state === "preparing" || state === "capturing" || state === "encoding";
354
+ const escapeCloses = !preparingEdits && (state === "idle" || state === "error" || state === "complete" && outputBlob !== null && savedOutput === outputBlob);
352
355
  useModalDialog({
353
356
  rootRef: overlayRef,
354
357
  dialogRef,
355
- closeOnEscape: false,
358
+ closeOnEscape: escapeCloses,
356
359
  onClose: handleClose
357
360
  });
358
361
  return /* @__PURE__ */ jsx(
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  VideoExportButton,
3
3
  VideoExportModal
4
- } from "../chunk-A6ED7EVY.js";
4
+ } from "../chunk-TUZLVOSP.js";
5
5
  import {
6
6
  CoverImageExportModal,
7
7
  coverImageFilename,
8
8
  validateCoverImageDimensions
9
- } from "../chunk-KJQVUVOG.js";
9
+ } from "../chunk-JDIMPME5.js";
10
10
  import "../chunk-3NJDHK62.js";
11
- import "../chunk-MI4EJXTD.js";
12
- import "../chunk-QJWEZRZS.js";
13
- import "../chunk-4GFZ3GUE.js";
14
- import "../chunk-GBIYYDMY.js";
11
+ import "../chunk-47ODXCBA.js";
12
+ import "../chunk-A52VG7RA.js";
13
+ import "../chunk-C7NEHV5X.js";
14
+ import "../chunk-ISYJJJXN.js";
15
15
  import "../chunk-5MFQMJ5Z.js";
16
16
  export {
17
17
  CoverImageExportModal,
@@ -2,10 +2,10 @@ import {
2
2
  CoverImageExportModal,
3
3
  coverImageFilename,
4
4
  validateCoverImageDimensions
5
- } from "../chunk-KJQVUVOG.js";
5
+ } from "../chunk-JDIMPME5.js";
6
6
  import "../chunk-3NJDHK62.js";
7
- import "../chunk-QJWEZRZS.js";
8
- import "../chunk-4GFZ3GUE.js";
7
+ import "../chunk-A52VG7RA.js";
8
+ import "../chunk-C7NEHV5X.js";
9
9
  export {
10
10
  CoverImageExportModal,
11
11
  coverImageFilename,
@@ -7,8 +7,8 @@ import {
7
7
  } from "../chunk-3NJDHK62.js";
8
8
  import {
9
9
  useFrameCapture
10
- } from "../chunk-QJWEZRZS.js";
11
- import "../chunk-4GFZ3GUE.js";
10
+ } from "../chunk-A52VG7RA.js";
11
+ import "../chunk-C7NEHV5X.js";
12
12
 
13
13
  // src/DashboardImageExportModal.tsx
14
14
  import { useCallback, useId, useMemo, useRef, useState } from "react";
@@ -1,5 +1,7 @@
1
1
  export { E as EncoderConfig, a as EncoderFrameSource, M as MainThreadEncoder, c as createEncoder, s as supportsWebCodecs, b as supportsWebCodecsH264 } from '../mainThreadEncoder-BVCLjlfj.js';
2
- export { FfmpegWasmLoadConfig } from '@bendyline/squisq-video';
2
+ import { AudioTimelineClip } from '@bendyline/squisq-video';
3
+ export { AudioTimelineClip, FfmpegWasmLoadConfig } from '@bendyline/squisq-video';
4
+ import { MediaScheduleOptions, Doc } from '@bendyline/squisq/schemas';
3
5
 
4
6
  /**
5
7
  * audioTrack — In-browser audio rendering + AAC encoding for MP4 export.
@@ -26,5 +28,127 @@ export { FfmpegWasmLoadConfig } from '@bendyline/squisq-video';
26
28
  * older Chromium) or the config is unsupported.
27
29
  */
28
30
  declare function supportsWebCodecsAac(sampleRate?: number, channels?: number): Promise<boolean>;
31
+ /**
32
+ * Mix a list of timeline clips into one `AudioBuffer`.
33
+ *
34
+ * Decodes each unique source once, then schedules an `AudioBufferSourceNode`
35
+ * per clip at its `startSec` with the trim window (`offset = sourceInSec`,
36
+ * `duration = durationSec`). Authored audio/narration sources must decode.
37
+ * Video sources are optional because a valid video can be silent: each is
38
+ * decoded independently, silent ones are skipped, and every audible video is
39
+ * connected to the same destination so overlapping tracks are mixed.
40
+ */
41
+ declare function renderAudioTimeline(clips: AudioTimelineClip[], buffers: Map<string, ArrayBuffer>, totalDurationSec: number, sampleRate?: number): Promise<AudioBuffer | null>;
42
+
43
+ /**
44
+ * Types and helpers shared by the audio-file encoder's WAV and lossy paths.
45
+ */
46
+ type AudioFileFormat = 'm4a' | 'opus-webm' | 'wav';
47
+ interface AudioFileEncoderOptions {
48
+ readonly format: AudioFileFormat;
49
+ /** Sample rate of the PCM passed to `append` (e.g. 24000 or 48000). */
50
+ readonly sampleRate: number;
51
+ readonly channels: 1 | 2;
52
+ /** Bits per second for lossy formats. Defaults depend on format and channel count. */
53
+ readonly bitrate?: number;
54
+ }
55
+ interface AudioFileEncoder {
56
+ readonly format: AudioFileFormat;
57
+ /** `'audio/mp4'` | `'audio/webm'` | `'audio/wav'` */
58
+ readonly mimeType: string;
59
+ /** `'m4a'` | `'webm'` | `'wav'` */
60
+ readonly extension: string;
61
+ /**
62
+ * Append planar float32 PCM, one Float32Array per channel, at
63
+ * `options.sampleRate`. Streams; never buffers the whole file in float32.
64
+ * Calls are serialized, but awaiting each one respects encoder backpressure.
65
+ */
66
+ append(channels: readonly Float32Array[]): Promise<void>;
67
+ /** Flush and return the finished file. */
68
+ finish(): Promise<Blob>;
69
+ /** Abandon the file and release encoder resources. */
70
+ cancel(): Promise<void>;
71
+ }
72
+
73
+ /**
74
+ * Streaming audio-file encoder: planar float32 PCM in, an M4A (AAC), Opus/WebM
75
+ * or WAV `Blob` out.
76
+ *
77
+ * - `m4a` — AAC in an audio-only MP4 (mediabunny's MP4 writer; unlike the
78
+ * video export's muxer it declares no video track). Needs a WebCodecs AAC
79
+ * encoder, which Linux Chromium lacks.
80
+ * - `opus-webm` — Opus in WebM, the container recorded takes already use.
81
+ * - `wav` — 16-bit PCM, always available, written by a streaming writer.
82
+ *
83
+ * Callers append blocks at their own sample rate. When the codec cannot encode
84
+ * that rate (WebCodecs AAC takes only 44.1/48 kHz; TTS commonly emits 24 kHz)
85
+ * the encoder resamples in-stream with a band-limited converter. Input is
86
+ * consumed in short slices, so appending even a whole document's buffer never
87
+ * allocates another copy of it; lossy output accumulates as encoded bytes only.
88
+ *
89
+ * The lossy path (mediabunny) sits behind a dynamic import, so WAV-only
90
+ * callers and the rest of the `/encoder` entry never load it.
91
+ */
92
+
93
+ /**
94
+ * Formats this runtime can encode. `'wav'` is always included; `'m4a'` needs a
95
+ * WebCodecs AAC encoder (absent on Linux Chromium) and `'opus-webm'` an Opus
96
+ * one. Ordered m4a, opus-webm, wav.
97
+ */
98
+ declare function supportedAudioFileFormats(): Promise<readonly AudioFileFormat[]>;
99
+ /**
100
+ * Create a streaming encoder for one audio file. Rejects when the runtime
101
+ * cannot encode the requested format (probe with
102
+ * {@link supportedAudioFileFormats} first); it never silently switches format.
103
+ */
104
+ declare function createAudioFileEncoder(options: AudioFileEncoderOptions): Promise<AudioFileEncoder>;
105
+
106
+ /**
107
+ * documentAudio — the doc → mixed `AudioBuffer` path shared by MP4 export and
108
+ * hosts that export a document's audio on its own.
109
+ *
110
+ * One pipeline, three steps, so the two consumers cannot drift:
111
+ *
112
+ * 1. {@link documentAudioTimeline} schedules every clip the doc plays —
113
+ * `doc.audio.segments`, `documentMedia` and `block.media` (including the
114
+ * audio of scheduled video) — via `computeAudioTimeline`, substituting
115
+ * media-edit renders through `processedAudio` exactly as video export does.
116
+ * 2. {@link loadAudioTimelineSources} reads each unique source once.
117
+ * 3. {@link mixAudioTimeline} renders the mix with `renderAudioTimeline`
118
+ * (OfflineAudioContext), at least as long as the doc's timeline.
119
+ *
120
+ * {@link renderDocumentAudio} composes the three for hosts.
121
+ */
122
+
123
+ interface RenderDocumentAudioOptions {
124
+ /** Read a media file referenced by the doc (relative src), or null if missing. */
125
+ readMedia(src: string): Promise<ArrayBuffer | null>;
126
+ /** Mix sample rate (default 48000). */
127
+ readonly sampleRate?: number;
128
+ readonly signal?: AbortSignal;
129
+ /**
130
+ * Media-edit render lookup (`fx` recipes), as `VideoExportConfig.processedAudio`:
131
+ * an edited clip mixes its processed render instead of its source. Hosts
132
+ * typically pass `createMediaEditRenderManager(...).processedAudio` after
133
+ * awaiting pending renders. Omitted → original audio everywhere.
134
+ */
135
+ readonly processedAudio?: MediaScheduleOptions['processedAudio'];
136
+ /**
137
+ * What to do when `readMedia` returns null for a scheduled source.
138
+ * `'error'` (default) rejects, naming the missing files; `'skip'` mixes
139
+ * whatever could be read.
140
+ */
141
+ readonly missingMedia?: 'error' | 'skip';
142
+ }
143
+ /**
144
+ * Mix every audio clip the doc schedules (`doc.audio.segments`,
145
+ * `documentMedia`, `block.media`) on the doc's timeline, honoring media-edit
146
+ * renders the same way video export does. The result spans the doc's duration
147
+ * (or the last clip's end, if later). Null when the doc has no audio.
148
+ *
149
+ * Pass the same prepared doc video export would get — narration timing and
150
+ * audio mapping already resolved (`resolveAudioMapping`).
151
+ */
152
+ declare function renderDocumentAudio(doc: Doc, options: RenderDocumentAudioOptions): Promise<AudioBuffer | null>;
29
153
 
30
- export { supportsWebCodecsAac };
154
+ export { type AudioFileEncoder, type AudioFileEncoderOptions, type AudioFileFormat, type RenderDocumentAudioOptions, createAudioFileEncoder, renderAudioTimeline, renderDocumentAudio, supportedAudioFileFormats, supportsWebCodecsAac };
@@ -1,12 +1,23 @@
1
+ import {
2
+ createAudioFileEncoder,
3
+ supportedAudioFileFormats
4
+ } from "../chunk-FMQI6WK2.js";
5
+ import "../chunk-2W6JQSIY.js";
1
6
  import {
2
7
  createEncoder,
8
+ renderAudioTimeline,
9
+ renderDocumentAudio,
3
10
  supportsWebCodecs,
4
11
  supportsWebCodecsAac,
5
12
  supportsWebCodecsH264
6
- } from "../chunk-GBIYYDMY.js";
13
+ } from "../chunk-ISYJJJXN.js";
7
14
  import "../chunk-5MFQMJ5Z.js";
8
15
  export {
16
+ createAudioFileEncoder,
9
17
  createEncoder,
18
+ renderAudioTimeline,
19
+ renderDocumentAudio,
20
+ supportedAudioFileFormats,
10
21
  supportsWebCodecs,
11
22
  supportsWebCodecsAac,
12
23
  supportsWebCodecsH264
@@ -3,12 +3,12 @@ import {
3
3
  resolveVideoCoverFramePlan,
4
4
  resolveVideoExportCover,
5
5
  useVideoExport
6
- } from "../chunk-MI4EJXTD.js";
6
+ } from "../chunk-47ODXCBA.js";
7
7
  import {
8
8
  useFrameCapture
9
- } from "../chunk-QJWEZRZS.js";
10
- import "../chunk-4GFZ3GUE.js";
11
- import "../chunk-GBIYYDMY.js";
9
+ } from "../chunk-A52VG7RA.js";
10
+ import "../chunk-C7NEHV5X.js";
11
+ import "../chunk-ISYJJJXN.js";
12
12
  import "../chunk-5MFQMJ5Z.js";
13
13
  export {
14
14
  DEFAULT_VIDEO_COVER_PRE_ROLL_SECONDS,
package/dist/index.d.ts CHANGED
@@ -3,8 +3,8 @@ export { CoverImageExportFormat, CoverImageExportModal, CoverImageExportModalPro
3
3
  export { D as DEFAULT_VIDEO_COVER_PRE_ROLL_SECONDS, R as ResolvedVideoExportCover, U as UseVideoExportOptions, V as VideoAudioPolicy, a as VideoCoverFramePlan, b as VideoExportConfig, c as VideoExportFramePreview, d as VideoExportResult, e as VideoExportState, f as VideoOutputFormat, r as resolveVideoCoverFramePlan, g as resolveVideoExportCover, u as useVideoExport } from './useVideoExport-DsNDpjmO.js';
4
4
  export { FrameCaptureHandle, FrameCaptureOptions, FrameCaptureRenderOptions, useFrameCapture } from './hooks/index.js';
5
5
  export { E as EncoderConfig, a as EncoderFrameSource, M as MainThreadEncoder, c as createEncoder, s as supportsWebCodecs, b as supportsWebCodecsH264 } from './mainThreadEncoder-BVCLjlfj.js';
6
- export { FfmpegWasmLoadConfig } from '@bendyline/squisq-video';
7
- export { supportsWebCodecsAac } from './encoder/index.js';
6
+ export { AudioTimelineClip, FfmpegWasmLoadConfig } from '@bendyline/squisq-video';
7
+ export { AudioFileEncoder, AudioFileEncoderOptions, AudioFileFormat, RenderDocumentAudioOptions, createAudioFileEncoder, renderAudioTimeline, renderDocumentAudio, supportedAudioFileFormats, supportsWebCodecsAac } from './encoder/index.js';
8
8
  export { M as MediaEditJobOptions, a as MediaEditPausesRequest, b as MediaEditPausesResult, c as MediaEditPreviewRequest, d as MediaEditPreviewResult, e as MediaEditRenderManager, f as MediaEditRenderManagerOptions, g as MediaEditRenderRequest, h as MediaEditRenderResult, i as MediaEditRenderState, j as MediaEditRenderStatus, k as MediaEditRenderer, l as MediaEditRendererOptions, m as createMediaEditRenderManager, n as createMediaEditRenderer } from './mediaEditRenderManager-W_o6RRhT.js';
9
9
  export { MediaEditRendersView, useMediaEditRenders, useMediaEditStatus, useProcessedAudio } from './media-edit/index.js';
10
10
  import 'react/jsx-runtime';
package/dist/index.js CHANGED
@@ -1,36 +1,43 @@
1
1
  import {
2
2
  VideoExportButton,
3
3
  VideoExportModal
4
- } from "./chunk-A6ED7EVY.js";
4
+ } from "./chunk-TUZLVOSP.js";
5
5
  import {
6
6
  CoverImageExportModal,
7
7
  coverImageFilename,
8
8
  validateCoverImageDimensions
9
- } from "./chunk-KJQVUVOG.js";
9
+ } from "./chunk-JDIMPME5.js";
10
10
  import "./chunk-3NJDHK62.js";
11
11
  import {
12
12
  DEFAULT_VIDEO_COVER_PRE_ROLL_SECONDS,
13
13
  resolveVideoCoverFramePlan,
14
14
  resolveVideoExportCover,
15
15
  useVideoExport
16
- } from "./chunk-MI4EJXTD.js";
16
+ } from "./chunk-47ODXCBA.js";
17
17
  import {
18
18
  useFrameCapture
19
- } from "./chunk-QJWEZRZS.js";
20
- import "./chunk-4GFZ3GUE.js";
19
+ } from "./chunk-A52VG7RA.js";
20
+ import "./chunk-C7NEHV5X.js";
21
+ import {
22
+ createAudioFileEncoder,
23
+ supportedAudioFileFormats
24
+ } from "./chunk-FMQI6WK2.js";
25
+ import "./chunk-2W6JQSIY.js";
21
26
  import {
22
27
  createEncoder,
28
+ renderAudioTimeline,
29
+ renderDocumentAudio,
23
30
  supportsWebCodecs,
24
31
  supportsWebCodecsAac,
25
32
  supportsWebCodecsH264
26
- } from "./chunk-GBIYYDMY.js";
33
+ } from "./chunk-ISYJJJXN.js";
27
34
  import {
28
35
  createMediaEditRenderManager,
29
36
  createMediaEditRenderer,
30
37
  useMediaEditRenders,
31
38
  useMediaEditStatus,
32
39
  useProcessedAudio
33
- } from "./chunk-JKWCZION.js";
40
+ } from "./chunk-OLFWEKY5.js";
34
41
  import "./chunk-TL2IMDIZ.js";
35
42
  import "./chunk-5MFQMJ5Z.js";
36
43
  export {
@@ -39,11 +46,15 @@ export {
39
46
  VideoExportButton,
40
47
  VideoExportModal,
41
48
  coverImageFilename,
49
+ createAudioFileEncoder,
42
50
  createEncoder,
43
51
  createMediaEditRenderManager,
44
52
  createMediaEditRenderer,
53
+ renderAudioTimeline,
54
+ renderDocumentAudio,
45
55
  resolveVideoCoverFramePlan,
46
56
  resolveVideoExportCover,
57
+ supportedAudioFileFormats,
47
58
  supportsWebCodecs,
48
59
  supportsWebCodecsAac,
49
60
  supportsWebCodecsH264,