canvas-recorder-lib 0.0.0-stage → 0.5.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/README.md +140 -2
- package/dev/audio-builder.ts +271 -0
- package/dev/canvas-recorder.css +369 -0
- package/dev/canvas-recorder.ts +7302 -0
- package/dev/color-picker.ts +432 -0
- package/dev/color-utils.ts +177 -0
- package/dev/component-picker.ts +151 -0
- package/dev/delay-files.ts +139 -0
- package/dev/font-utils.ts +256 -0
- package/dev/font-widgets.ts +358 -0
- package/dev/fourier-panel.ts +151 -0
- package/dev/handwriting-panel.ts +405 -0
- package/dev/multi-text-panel.ts +224 -0
- package/dev/player-body.ts +382 -0
- package/dev/rect-snap.ts +154 -0
- package/dev/schedule-helpers.ts +332 -0
- package/dev/slide-panel.ts +57 -0
- package/dev/sound-clips.ts +198 -0
- package/dev/split-dialog.ts +493 -0
- package/dev/static-image-panel.ts +254 -0
- package/dev/style.css +41 -0
- package/dev/synced-file.ts +351 -0
- package/dev/timeline-display.ts +836 -0
- package/dev/transcribe-core.ts +305 -0
- package/dev/transcribe-worker.ts +83 -0
- package/dev/transcript-align.ts +641 -0
- package/dev/transcript-export.ts +114 -0
- package/dev/transcript-view.ts +632 -0
- package/dev/transcripts.ts +362 -0
- package/dev/video-clip-panel.ts +515 -0
- package/dist/dev/audio-builder.d.ts +89 -0
- package/dist/dev/audio-builder.d.ts.map +1 -0
- package/dist/dev/audio-builder.js +227 -0
- package/dist/dev/audio-builder.js.map +1 -0
- package/dist/dev/canvas-recorder.css +369 -0
- package/dist/dev/canvas-recorder.d.ts +2 -0
- package/dist/dev/canvas-recorder.d.ts.map +1 -0
- package/dist/dev/canvas-recorder.js +6274 -0
- package/dist/dev/canvas-recorder.js.map +1 -0
- package/dist/dev/color-picker.d.ts +5 -0
- package/dist/dev/color-picker.d.ts.map +1 -0
- package/dist/dev/color-picker.js +348 -0
- package/dist/dev/color-picker.js.map +1 -0
- package/dist/dev/color-utils.d.ts +34 -0
- package/dist/dev/color-utils.d.ts.map +1 -0
- package/dist/dev/color-utils.js +154 -0
- package/dist/dev/color-utils.js.map +1 -0
- package/dist/dev/component-picker.d.ts +19 -0
- package/dist/dev/component-picker.d.ts.map +1 -0
- package/dist/dev/component-picker.js +135 -0
- package/dist/dev/component-picker.js.map +1 -0
- package/dist/dev/delay-files.d.ts +23 -0
- package/dist/dev/delay-files.d.ts.map +1 -0
- package/dist/dev/delay-files.js +117 -0
- package/dist/dev/delay-files.js.map +1 -0
- package/dist/dev/font-utils.d.ts +50 -0
- package/dist/dev/font-utils.d.ts.map +1 -0
- package/dist/dev/font-utils.js +230 -0
- package/dist/dev/font-utils.js.map +1 -0
- package/dist/dev/font-widgets.d.ts +24 -0
- package/dist/dev/font-widgets.d.ts.map +1 -0
- package/dist/dev/font-widgets.js +299 -0
- package/dist/dev/font-widgets.js.map +1 -0
- package/dist/dev/fourier-panel.d.ts +13 -0
- package/dist/dev/fourier-panel.d.ts.map +1 -0
- package/dist/dev/fourier-panel.js +73 -0
- package/dist/dev/fourier-panel.js.map +1 -0
- package/dist/dev/handwriting-panel.d.ts +44 -0
- package/dist/dev/handwriting-panel.d.ts.map +1 -0
- package/dist/dev/handwriting-panel.js +305 -0
- package/dist/dev/handwriting-panel.js.map +1 -0
- package/dist/dev/multi-text-panel.d.ts +38 -0
- package/dist/dev/multi-text-panel.d.ts.map +1 -0
- package/dist/dev/multi-text-panel.js +151 -0
- package/dist/dev/multi-text-panel.js.map +1 -0
- package/dist/dev/player-body.d.ts +3 -0
- package/dist/dev/player-body.d.ts.map +1 -0
- package/dist/dev/player-body.js +382 -0
- package/dist/dev/player-body.js.map +1 -0
- package/dist/dev/rect-snap.d.ts +40 -0
- package/dist/dev/rect-snap.d.ts.map +1 -0
- package/dist/dev/rect-snap.js +115 -0
- package/dist/dev/rect-snap.js.map +1 -0
- package/dist/dev/schedule-helpers.d.ts +26 -0
- package/dist/dev/schedule-helpers.d.ts.map +1 -0
- package/dist/dev/schedule-helpers.js +296 -0
- package/dist/dev/schedule-helpers.js.map +1 -0
- package/dist/dev/slide-panel.d.ts +8 -0
- package/dist/dev/slide-panel.d.ts.map +1 -0
- package/dist/dev/slide-panel.js +47 -0
- package/dist/dev/slide-panel.js.map +1 -0
- package/dist/dev/sound-clips.d.ts +57 -0
- package/dist/dev/sound-clips.d.ts.map +1 -0
- package/dist/dev/sound-clips.js +175 -0
- package/dist/dev/sound-clips.js.map +1 -0
- package/dist/dev/split-dialog.d.ts +49 -0
- package/dist/dev/split-dialog.d.ts.map +1 -0
- package/dist/dev/split-dialog.js +399 -0
- package/dist/dev/split-dialog.js.map +1 -0
- package/dist/dev/static-image-panel.d.ts +31 -0
- package/dist/dev/static-image-panel.d.ts.map +1 -0
- package/dist/dev/static-image-panel.js +205 -0
- package/dist/dev/static-image-panel.js.map +1 -0
- package/dist/dev/style.css +41 -0
- package/dist/dev/synced-file.d.ts +71 -0
- package/dist/dev/synced-file.d.ts.map +1 -0
- package/dist/dev/synced-file.js +287 -0
- package/dist/dev/synced-file.js.map +1 -0
- package/dist/dev/timeline-display.d.ts +172 -0
- package/dist/dev/timeline-display.d.ts.map +1 -0
- package/dist/dev/timeline-display.js +688 -0
- package/dist/dev/timeline-display.js.map +1 -0
- package/dist/dev/transcribe-core.d.ts +63 -0
- package/dist/dev/transcribe-core.d.ts.map +1 -0
- package/dist/dev/transcribe-core.js +226 -0
- package/dist/dev/transcribe-core.js.map +1 -0
- package/dist/dev/transcribe-worker.d.ts +26 -0
- package/dist/dev/transcribe-worker.d.ts.map +1 -0
- package/dist/dev/transcribe-worker.js +48 -0
- package/dist/dev/transcribe-worker.js.map +1 -0
- package/dist/dev/transcript-align.d.ts +205 -0
- package/dist/dev/transcript-align.d.ts.map +1 -0
- package/dist/dev/transcript-align.js +497 -0
- package/dist/dev/transcript-align.js.map +1 -0
- package/dist/dev/transcript-export.d.ts +28 -0
- package/dist/dev/transcript-export.d.ts.map +1 -0
- package/dist/dev/transcript-export.js +82 -0
- package/dist/dev/transcript-export.js.map +1 -0
- package/dist/dev/transcript-view.d.ts +74 -0
- package/dist/dev/transcript-view.d.ts.map +1 -0
- package/dist/dev/transcript-view.js +556 -0
- package/dist/dev/transcript-view.js.map +1 -0
- package/dist/dev/transcripts.d.ts +65 -0
- package/dist/dev/transcripts.d.ts.map +1 -0
- package/dist/dev/transcripts.js +292 -0
- package/dist/dev/transcripts.js.map +1 -0
- package/dist/dev/video-clip-panel.d.ts +39 -0
- package/dist/dev/video-clip-panel.d.ts.map +1 -0
- package/dist/dev/video-clip-panel.js +411 -0
- package/dist/dev/video-clip-panel.js.map +1 -0
- package/dist/lib/index.d.ts +34 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +39 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/main-control.d.ts +89 -0
- package/dist/lib/main-control.d.ts.map +1 -0
- package/dist/lib/main-control.js +111 -0
- package/dist/lib/main-control.js.map +1 -0
- package/dist/src/binary-search.d.ts +206 -0
- package/dist/src/binary-search.d.ts.map +1 -0
- package/dist/src/binary-search.js +456 -0
- package/dist/src/binary-search.js.map +1 -0
- package/dist/src/cross-fade.d.ts +69 -0
- package/dist/src/cross-fade.d.ts.map +1 -0
- package/dist/src/cross-fade.js +113 -0
- package/dist/src/cross-fade.js.map +1 -0
- package/dist/src/debug-log.d.ts +22 -0
- package/dist/src/debug-log.d.ts.map +1 -0
- package/dist/src/debug-log.js +32 -0
- package/dist/src/debug-log.js.map +1 -0
- package/dist/src/glib/Cursive.json +444 -0
- package/dist/src/glib/Futura L.json +406 -0
- package/dist/src/glib/grid.d.ts +61 -0
- package/dist/src/glib/grid.d.ts.map +1 -0
- package/dist/src/glib/grid.js +134 -0
- package/dist/src/glib/grid.js.map +1 -0
- package/dist/src/glib/letters-base.d.ts +166 -0
- package/dist/src/glib/letters-base.d.ts.map +1 -0
- package/dist/src/glib/letters-base.js +185 -0
- package/dist/src/glib/letters-base.js.map +1 -0
- package/dist/src/glib/line-font.d.ts +181 -0
- package/dist/src/glib/line-font.d.ts.map +1 -0
- package/dist/src/glib/line-font.js +2978 -0
- package/dist/src/glib/line-font.js.map +1 -0
- package/dist/src/glib/my-rainbow.d.ts +126 -0
- package/dist/src/glib/my-rainbow.d.ts.map +1 -0
- package/dist/src/glib/my-rainbow.js +132 -0
- package/dist/src/glib/my-rainbow.js.map +1 -0
- package/dist/src/glib/paragraph-layout.d.ts +122 -0
- package/dist/src/glib/paragraph-layout.d.ts.map +1 -0
- package/dist/src/glib/paragraph-layout.js +377 -0
- package/dist/src/glib/paragraph-layout.js.map +1 -0
- package/dist/src/glib/path-shape-splitter.d.ts +114 -0
- package/dist/src/glib/path-shape-splitter.d.ts.map +1 -0
- package/dist/src/glib/path-shape-splitter.js +334 -0
- package/dist/src/glib/path-shape-splitter.js.map +1 -0
- package/dist/src/glib/path-shape.d.ts +890 -0
- package/dist/src/glib/path-shape.d.ts.map +1 -0
- package/dist/src/glib/path-shape.js +2276 -0
- package/dist/src/glib/path-shape.js.map +1 -0
- package/dist/src/glib/transforms.d.ts +65 -0
- package/dist/src/glib/transforms.d.ts.map +1 -0
- package/dist/src/glib/transforms.js +223 -0
- package/dist/src/glib/transforms.js.map +1 -0
- package/dist/src/interpolate.d.ts +216 -0
- package/dist/src/interpolate.d.ts.map +1 -0
- package/dist/src/interpolate.js +480 -0
- package/dist/src/interpolate.js.map +1 -0
- package/dist/src/lattice.d.ts +71 -0
- package/dist/src/lattice.d.ts.map +1 -0
- package/dist/src/lattice.js +108 -0
- package/dist/src/lattice.js.map +1 -0
- package/dist/src/morph-animation.d.ts +31 -0
- package/dist/src/morph-animation.d.ts.map +1 -0
- package/dist/src/morph-animation.js +441 -0
- package/dist/src/morph-animation.js.map +1 -0
- package/dist/src/peano-fourier/fourier-shared.d.ts +97 -0
- package/dist/src/peano-fourier/fourier-shared.d.ts.map +1 -0
- package/dist/src/peano-fourier/fourier-shared.js +538 -0
- package/dist/src/peano-fourier/fourier-shared.js.map +1 -0
- package/dist/src/schedule-helper.d.ts +216 -0
- package/dist/src/schedule-helper.d.ts.map +1 -0
- package/dist/src/schedule-helper.js +396 -0
- package/dist/src/schedule-helper.js.map +1 -0
- package/dist/src/showable.d.ts +757 -0
- package/dist/src/showable.d.ts.map +1 -0
- package/dist/src/showable.js +399 -0
- package/dist/src/showable.js.map +1 -0
- package/dist/src/slide-components/arrow.d.ts +36 -0
- package/dist/src/slide-components/arrow.d.ts.map +1 -0
- package/dist/src/slide-components/arrow.js +80 -0
- package/dist/src/slide-components/arrow.js.map +1 -0
- package/dist/src/slide-components/cross-fade-transition.d.ts +25 -0
- package/dist/src/slide-components/cross-fade-transition.d.ts.map +1 -0
- package/dist/src/slide-components/cross-fade-transition.js +109 -0
- package/dist/src/slide-components/cross-fade-transition.js.map +1 -0
- package/dist/src/slide-components/duration-agnostic.d.ts +23 -0
- package/dist/src/slide-components/duration-agnostic.d.ts.map +1 -0
- package/dist/src/slide-components/duration-agnostic.js +27 -0
- package/dist/src/slide-components/duration-agnostic.js.map +1 -0
- package/dist/src/slide-components/fixed-duration.d.ts +19 -0
- package/dist/src/slide-components/fixed-duration.d.ts.map +1 -0
- package/dist/src/slide-components/fixed-duration.js +24 -0
- package/dist/src/slide-components/fixed-duration.js.map +1 -0
- package/dist/src/slide-components/fourier.d.ts +175 -0
- package/dist/src/slide-components/fourier.d.ts.map +1 -0
- package/dist/src/slide-components/fourier.js +373 -0
- package/dist/src/slide-components/fourier.js.map +1 -0
- package/dist/src/slide-components/frame-counter.d.ts +15 -0
- package/dist/src/slide-components/frame-counter.d.ts.map +1 -0
- package/dist/src/slide-components/frame-counter.js +50 -0
- package/dist/src/slide-components/frame-counter.js.map +1 -0
- package/dist/src/slide-components/function-graph.d.ts +30 -0
- package/dist/src/slide-components/function-graph.d.ts.map +1 -0
- package/dist/src/slide-components/function-graph.js +111 -0
- package/dist/src/slide-components/function-graph.js.map +1 -0
- package/dist/src/slide-components/halftone-shadow.d.ts +36 -0
- package/dist/src/slide-components/halftone-shadow.d.ts.map +1 -0
- package/dist/src/slide-components/halftone-shadow.js +111 -0
- package/dist/src/slide-components/halftone-shadow.js.map +1 -0
- package/dist/src/slide-components/handwriting-effect.d.ts +94 -0
- package/dist/src/slide-components/handwriting-effect.d.ts.map +1 -0
- package/dist/src/slide-components/handwriting-effect.js +175 -0
- package/dist/src/slide-components/handwriting-effect.js.map +1 -0
- package/dist/src/slide-components/hold.d.ts +36 -0
- package/dist/src/slide-components/hold.d.ts.map +1 -0
- package/dist/src/slide-components/hold.js +48 -0
- package/dist/src/slide-components/hold.js.map +1 -0
- package/dist/src/slide-components/image.d.ts +30 -0
- package/dist/src/slide-components/image.d.ts.map +1 -0
- package/dist/src/slide-components/image.js +73 -0
- package/dist/src/slide-components/image.js.map +1 -0
- package/dist/src/slide-components/in-parallel.d.ts +243 -0
- package/dist/src/slide-components/in-parallel.d.ts.map +1 -0
- package/dist/src/slide-components/in-parallel.js +468 -0
- package/dist/src/slide-components/in-parallel.js.map +1 -0
- package/dist/src/slide-components/in-series.d.ts +56 -0
- package/dist/src/slide-components/in-series.d.ts.map +1 -0
- package/dist/src/slide-components/in-series.js +184 -0
- package/dist/src/slide-components/in-series.js.map +1 -0
- package/dist/src/slide-components/live-duration.d.ts +19 -0
- package/dist/src/slide-components/live-duration.d.ts.map +1 -0
- package/dist/src/slide-components/live-duration.js +31 -0
- package/dist/src/slide-components/live-duration.js.map +1 -0
- package/dist/src/slide-components/multi-text.d.ts +403 -0
- package/dist/src/slide-components/multi-text.d.ts.map +1 -0
- package/dist/src/slide-components/multi-text.js +877 -0
- package/dist/src/slide-components/multi-text.js.map +1 -0
- package/dist/src/slide-components/rectangle.d.ts +23 -0
- package/dist/src/slide-components/rectangle.d.ts.map +1 -0
- package/dist/src/slide-components/rectangle.js +32 -0
- package/dist/src/slide-components/rectangle.js.map +1 -0
- package/dist/src/slide-components/registry.d.ts +90 -0
- package/dist/src/slide-components/registry.d.ts.map +1 -0
- package/dist/src/slide-components/registry.js +319 -0
- package/dist/src/slide-components/registry.js.map +1 -0
- package/dist/src/slide-components/serialize.d.ts +35 -0
- package/dist/src/slide-components/serialize.d.ts.map +1 -0
- package/dist/src/slide-components/serialize.js +39 -0
- package/dist/src/slide-components/serialize.js.map +1 -0
- package/dist/src/slide-components/show-error.d.ts +8 -0
- package/dist/src/slide-components/show-error.d.ts.map +1 -0
- package/dist/src/slide-components/show-error.js +27 -0
- package/dist/src/slide-components/show-error.js.map +1 -0
- package/dist/src/slide-components/simple-text.d.ts +30 -0
- package/dist/src/slide-components/simple-text.d.ts.map +1 -0
- package/dist/src/slide-components/simple-text.js +101 -0
- package/dist/src/slide-components/simple-text.js.map +1 -0
- package/dist/src/slide-components/slide-component.d.ts +58 -0
- package/dist/src/slide-components/slide-component.d.ts.map +1 -0
- package/dist/src/slide-components/slide-component.js +154 -0
- package/dist/src/slide-components/slide-component.js.map +1 -0
- package/dist/src/slide-components/slide-left.d.ts +18 -0
- package/dist/src/slide-components/slide-left.d.ts.map +1 -0
- package/dist/src/slide-components/slide-left.js +40 -0
- package/dist/src/slide-components/slide-left.js.map +1 -0
- package/dist/src/slide-components/split-video-clip.d.ts +82 -0
- package/dist/src/slide-components/split-video-clip.d.ts.map +1 -0
- package/dist/src/slide-components/split-video-clip.js +178 -0
- package/dist/src/slide-components/split-video-clip.js.map +1 -0
- package/dist/src/slide-components/text-effect.d.ts +83 -0
- package/dist/src/slide-components/text-effect.d.ts.map +1 -0
- package/dist/src/slide-components/text-effect.js +20 -0
- package/dist/src/slide-components/text-effect.js.map +1 -0
- package/dist/src/slide-components/traditional-text.d.ts +129 -0
- package/dist/src/slide-components/traditional-text.d.ts.map +1 -0
- package/dist/src/slide-components/traditional-text.js +313 -0
- package/dist/src/slide-components/traditional-text.js.map +1 -0
- package/dist/src/slide-components/video-clip.d.ts +63 -0
- package/dist/src/slide-components/video-clip.d.ts.map +1 -0
- package/dist/src/slide-components/video-clip.js +564 -0
- package/dist/src/slide-components/video-clip.js.map +1 -0
- package/dist/src/slide-components/video-info.d.ts +81 -0
- package/dist/src/slide-components/video-info.d.ts.map +1 -0
- package/dist/src/slide-components/video-info.js +111 -0
- package/dist/src/slide-components/video-info.js.map +1 -0
- package/dist/src/slow-image-sources.d.ts +87 -0
- package/dist/src/slow-image-sources.d.ts.map +1 -0
- package/dist/src/slow-image-sources.js +148 -0
- package/dist/src/slow-image-sources.js.map +1 -0
- package/dist/src/snapshot.d.ts +129 -0
- package/dist/src/snapshot.d.ts.map +1 -0
- package/dist/src/snapshot.js +431 -0
- package/dist/src/snapshot.js.map +1 -0
- package/dist/src/stroke-colors.d.ts +84 -0
- package/dist/src/stroke-colors.d.ts.map +1 -0
- package/dist/src/stroke-colors.js +360 -0
- package/dist/src/stroke-colors.js.map +1 -0
- package/dist/src/utility.d.ts +267 -0
- package/dist/src/utility.d.ts.map +1 -0
- package/dist/src/utility.js +647 -0
- package/dist/src/utility.js.map +1 -0
- package/dist/src/zipper.d.ts +38 -0
- package/dist/src/zipper.d.ts.map +1 -0
- package/dist/src/zipper.js +109 -0
- package/dist/src/zipper.js.map +1 -0
- package/imported-files.txt +85 -0
- package/internals.md +439 -0
- package/lib/index.ts +41 -0
- package/lib/main-control.ts +145 -0
- package/package.json +54 -4
- package/src/binary-search.ts +480 -0
- package/src/cross-fade.ts +146 -0
- package/src/debug-log.ts +40 -0
- package/src/glib/Cursive.json +444 -0
- package/src/glib/Futura L.json +406 -0
- package/src/glib/grid.ts +215 -0
- package/src/glib/letters-base.ts +242 -0
- package/src/glib/line-font.ts +3344 -0
- package/src/glib/my-rainbow.ts +217 -0
- package/src/glib/paragraph-layout.ts +407 -0
- package/src/glib/path-shape-splitter.ts +380 -0
- package/src/glib/path-shape.ts +2838 -0
- package/src/glib/transforms.ts +280 -0
- package/src/interpolate.ts +598 -0
- package/src/lattice.ts +157 -0
- package/src/morph-animation.ts +481 -0
- package/src/peano-fourier/fft-js.d.ts +3 -0
- package/src/peano-fourier/fourier-shared.ts +653 -0
- package/src/schedule-helper.ts +429 -0
- package/src/showable.ts +1050 -0
- package/src/slide-components/arrow.ts +115 -0
- package/src/slide-components/cross-fade-transition.ts +122 -0
- package/src/slide-components/duration-agnostic.ts +36 -0
- package/src/slide-components/fixed-duration.ts +24 -0
- package/src/slide-components/fourier.ts +514 -0
- package/src/slide-components/frame-counter.ts +55 -0
- package/src/slide-components/function-graph.ts +149 -0
- package/src/slide-components/halftone-shadow.ts +144 -0
- package/src/slide-components/handwriting-effect.ts +230 -0
- package/src/slide-components/hold.ts +72 -0
- package/src/slide-components/image.ts +87 -0
- package/src/slide-components/in-parallel.ts +590 -0
- package/src/slide-components/in-series.ts +235 -0
- package/src/slide-components/live-duration.ts +31 -0
- package/src/slide-components/multi-text.ts +1123 -0
- package/src/slide-components/rectangle.ts +41 -0
- package/src/slide-components/registry.ts +422 -0
- package/src/slide-components/serialize.ts +68 -0
- package/src/slide-components/show-error.ts +28 -0
- package/src/slide-components/simple-text.ts +157 -0
- package/src/slide-components/slide-component.ts +197 -0
- package/src/slide-components/slide-left.ts +51 -0
- package/src/slide-components/split-video-clip.ts +228 -0
- package/src/slide-components/text-effect.ts +93 -0
- package/src/slide-components/traditional-text.ts +378 -0
- package/src/slide-components/video-clip.ts +682 -0
- package/src/slide-components/video-info.ts +176 -0
- package/src/slow-image-sources.ts +167 -0
- package/src/snapshot.ts +547 -0
- package/src/stroke-colors.ts +495 -0
- package/src/utility.ts +724 -0
- package/src/zipper.ts +134 -0
package/README.md
CHANGED
|
@@ -1,3 +1,141 @@
|
|
|
1
|
-
#
|
|
1
|
+
# canvas-recorder-lib
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Preview, edit, annotate and record HTML canvas animations.
|
|
4
|
+
This is the tooling from [canvas-recorder](https://github.com/TradeIdeasPhilip/canvas-recorder), packaged as a library, so each video can be its own small project.
|
|
5
|
+
|
|
6
|
+
**Status:** version 0.x, a first version. Expect breaking changes.
|
|
7
|
+
|
|
8
|
+
**API docs:** https://tradeideasphilip.github.io/canvas-recorder-lib/
|
|
9
|
+
|
|
10
|
+
## Use
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { canvasRecorder } from "canvas-recorder-lib";
|
|
14
|
+
import { myVideo } from "./my-video.ts"; // Any Showable.
|
|
15
|
+
|
|
16
|
+
// Optional. The defaults are 3840 × 2160 pixels, 16 × 9 units, 60 fps.
|
|
17
|
+
// canvasRecorder.pixelWidth = 1920;
|
|
18
|
+
// canvasRecorder.pixelHeight = 1080;
|
|
19
|
+
|
|
20
|
+
canvasRecorder.start(myVideo, { name: "my-video" });
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`start()` replaces the page's `<body>` with the player and its Visual Editor.
|
|
24
|
+
Leave your HTML's body empty, or put "Please wait…" in it.
|
|
25
|
+
|
|
26
|
+
- Don't `await` `start()` at the top level of your main module. The page would hang with no error message.
|
|
27
|
+
- `name` keeps this video's saved editor state separate from other videos served from the same origin.
|
|
28
|
+
|
|
29
|
+
Imports:
|
|
30
|
+
|
|
31
|
+
- `canvas-recorder-lib` exports the main control object and the common building blocks.
|
|
32
|
+
- Anything else is available by path, e.g. `canvas-recorder-lib/src/glib/path-shape`.
|
|
33
|
+
|
|
34
|
+
The package includes the TypeScript source next to the compiled JavaScript, and Go to Definition takes you to the source.
|
|
35
|
+
|
|
36
|
+
## Notes for a project that uses this library
|
|
37
|
+
|
|
38
|
+
Things the first project to use this library ([riemann-surfaces-3d](https://github.com/TradeIdeasPhilip/riemann-surfaces-3d)) ran into.
|
|
39
|
+
|
|
40
|
+
### Vite setup
|
|
41
|
+
|
|
42
|
+
While both projects are on your disk, link the library with `"canvas-recorder-lib": "file:../canvas-recorder-lib"` in package.json.
|
|
43
|
+
Then add this to your `vite.config.js`:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import { defineConfig, searchForWorkspaceRoot } from "vite";
|
|
47
|
+
|
|
48
|
+
export default defineConfig({
|
|
49
|
+
server: {
|
|
50
|
+
port: 5174, // Pick one per project, and keep it.
|
|
51
|
+
strictPort: true,
|
|
52
|
+
fs: {
|
|
53
|
+
allow: [searchForWorkspaceRoot(process.cwd()), "../canvas-recorder-lib"],
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- **`fs.allow`:** without it, the server console says the transcription worker is "outside of Vite serving allow list", and transcripts fail.
|
|
60
|
+
A linked library lives outside your project. Vite serves files that are imported, but the worker is loaded by URL.
|
|
61
|
+
Setting `allow` turns off Vite's default, so your own folder has to be listed too; that's what `searchForWorkspaceRoot()` is for.
|
|
62
|
+
- **A fixed port:** the editor saves your work in the browser (IndexedDB), and the browser keeps a separate copy for each origin.
|
|
63
|
+
If another project already has the port, Vite quietly moves to the next one (5173 → 5174), and the editor seems to forget everything.
|
|
64
|
+
`strictPort` makes that an error instead.
|
|
65
|
+
- **`npm run watch`:** your project uses the library's compiled `dist/`, so keep this running in the library while you change it.
|
|
66
|
+
|
|
67
|
+
### Ports
|
|
68
|
+
|
|
69
|
+
Each project that uses this library gets its own port, forever.
|
|
70
|
+
Changing the port loses the editor's saved work, because IndexedDB belongs to the origin, and the port is part of the origin.
|
|
71
|
+
For a new project, take the next number and add it here.
|
|
72
|
+
|
|
73
|
+
| Port | Project |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| 5173 | [canvas-recorder](https://github.com/TradeIdeasPhilip/canvas-recorder) (Vite's default; historical) |
|
|
76
|
+
| 5174 | [riemann-surfaces-3d](https://github.com/TradeIdeasPhilip/riemann-surfaces-3d) |
|
|
77
|
+
| 5175 | [affine-transforms](https://github.com/TradeIdeasPhilip/affine-transforms) |
|
|
78
|
+
| 5176 | `test-project/` in this repo (planned; see [development-plans/test-project.md](development-plans/test-project.md)) |
|
|
79
|
+
|
|
80
|
+
### Starting the editor
|
|
81
|
+
|
|
82
|
+
- **Load the library only when you need it,** e.g. `await import("./video-editor")` from a button.
|
|
83
|
+
The rest of your program never pays for it.
|
|
84
|
+
- **Don't `await canvasRecorder.start()` at the top level of a module.** The page hangs with no error message.
|
|
85
|
+
- **Turn off your own CSS first.** `start()` replaces your `<body>`, but your stylesheets are still there, and they restyle the editor.
|
|
86
|
+
Disabling every sheet that has more than `@font-face` rules works (see `hideOurStyles()` in riemann-surfaces-3d's `src/video-editor.ts`).
|
|
87
|
+
- **Stop your own animation loop and keyboard handlers.** Otherwise typing in the Visual Editor's text boxes drives your program.
|
|
88
|
+
- **Put sound files in your `public/` folder** and refer to them as `"./name.m4a"`.
|
|
89
|
+
- **Save the editor's state into your project, so it's in git.** The editor always saves inside the browser (IndexedDB), which git can't see.
|
|
90
|
+
Make a `properties/` folder, and point **💾 Save As**, the **Save defaults** checkbox, and **Save Diffs** at it.
|
|
91
|
+
The browser remembers each choice, so after the first time they keep saving there.
|
|
92
|
+
Add a `properties/README.md` explaining the three files; copy [riemann-surfaces-3d's](https://github.com/TradeIdeasPhilip/riemann-surfaces-3d/blob/master/properties/README.md).
|
|
93
|
+
- **Register your own components** with `componentRegistry.set(key, { create })`.
|
|
94
|
+
Then the Visual Editor can add, save and load them, and "TypeScript defaults" can rebuild them.
|
|
95
|
+
|
|
96
|
+
### Recording a program that has its own state
|
|
97
|
+
|
|
98
|
+
Most of canvas-recorder's components draw any time you ask, in any order.
|
|
99
|
+
A program that steps its own animation forward (physics, a game loop, three.js robots with smooth walking) can't do that.
|
|
100
|
+
riemann-surfaces-3d's `src/full-screen-component.ts` handles this, and it's meant to be copied as is. What it learned:
|
|
101
|
+
|
|
102
|
+
- **Step with a fixed dt** (1 / `canvasRecorder.fps`), never the clock. Then recording, preview and every re-run match.
|
|
103
|
+
- **Going backwards means restart and replay.** Recording always moves forward, so it's always exact.
|
|
104
|
+
The live preview spends a few milliseconds per frame catching up, and shows a warning light until it does.
|
|
105
|
+
- **Take one step right after a restart.** Many programs only update their scene (camera, headings) when they step.
|
|
106
|
+
Without that step, frame 0 shows whatever was on screen before the restart, and jumps to frame 1.
|
|
107
|
+
- **Parents call `getFramePromises()` on every child, even ones that aren't on screen.**
|
|
108
|
+
A component that steps a program there must ignore times outside `0` to `duration`, or two of them in a series will keep restarting each other.
|
|
109
|
+
- **Only the player calls `show()`.** There are no thumbnails or other random-time calls.
|
|
110
|
+
|
|
111
|
+
### Size
|
|
112
|
+
|
|
113
|
+
The transcription feature brings a 27 MB speech-recognition file (`ort-wasm…wasm`) into your production build.
|
|
114
|
+
It is only downloaded if someone uses transcription.
|
|
115
|
+
|
|
116
|
+
## How this library is made
|
|
117
|
+
|
|
118
|
+
canvas-recorder is the source of truth.
|
|
119
|
+
`npm run import` copies the player, and everything it imports, from `../canvas-recorder` into `dev/` and `src/`, verbatim.
|
|
120
|
+
The library's own code lives in `lib/`.
|
|
121
|
+
|
|
122
|
+
To pick up newer code from canvas-recorder:
|
|
123
|
+
|
|
124
|
+
1. Make a branch from the previous "Verbatim import from canvas-recorder …" commit.
|
|
125
|
+
2. Run `npm run import`, and commit: "Verbatim import from canvas-recorder <hash>".
|
|
126
|
+
3. Merge that branch into master.
|
|
127
|
+
The library's hand edits stay as they are, and history only grows, so a plain `git push` works.
|
|
128
|
+
4. `npm run build`, and bump the version in package.json.
|
|
129
|
+
|
|
130
|
+
`imported-files.txt` lists what was copied, and from which commit.
|
|
131
|
+
|
|
132
|
+
## Build
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
npm install
|
|
136
|
+
npm run build # or: npm run watch
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Output goes to `dist/`: `.js`, `.d.ts`, source maps, plus the CSS and JSON files the JavaScript imports.
|
|
140
|
+
|
|
141
|
+
A project that depends on this library through `"canvas-recorder-lib": "file:../canvas-recorder-lib"` sees a change as soon as `npm run watch` recompiles it.
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This creates a complete audio clip by joining multiple clips.
|
|
3
|
+
* It starts with all silence and you can add the clips wherever you need them.
|
|
4
|
+
*
|
|
5
|
+
* Overlapping clips are mixed: each one is added to whatever is already
|
|
6
|
+
* there, so two sounds at the same time are both heard.
|
|
7
|
+
*
|
|
8
|
+
* The result is always **mono**. Every source is mixed down to one channel as
|
|
9
|
+
* it is added. Nothing recorded for these videos is really stereo: a Mac
|
|
10
|
+
* screen recording, for example, writes its one microphone signal into both
|
|
11
|
+
* channels, and CapCut's exports have done the same. One channel is less to
|
|
12
|
+
* test and can't put a sound in only one ear by accident.
|
|
13
|
+
*/
|
|
14
|
+
export class AudioBuilder {
|
|
15
|
+
/**
|
|
16
|
+
* Like AudioContext, but this lets you process data at full speed.
|
|
17
|
+
* AudioContext doesn't allow you to process things faster than realtime.
|
|
18
|
+
*/
|
|
19
|
+
private audioContext: OfflineAudioContext;
|
|
20
|
+
/**
|
|
21
|
+
* This is the sound we are building.
|
|
22
|
+
*/
|
|
23
|
+
private buffer: AudioBuffer;
|
|
24
|
+
|
|
25
|
+
getAudioBuffer(): AudioBuffer {
|
|
26
|
+
return this.buffer;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
constructor(totalDurationMs: number) {
|
|
30
|
+
const sampleRate = 48000;
|
|
31
|
+
// OfflineAudioContext requires length >= 1 -- a project can legitimately
|
|
32
|
+
// start out at duration 0 (e.g. an empty timeline before any clips have
|
|
33
|
+
// been added yet), so clamp rather than let the constructor throw.
|
|
34
|
+
this.audioContext = new OfflineAudioContext({
|
|
35
|
+
length: Math.max(1, totalDurationMs * 1000),
|
|
36
|
+
sampleRate,
|
|
37
|
+
});
|
|
38
|
+
const totalSamples = Math.max(
|
|
39
|
+
1,
|
|
40
|
+
Math.ceil((totalDurationMs / 1000) * sampleRate),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
this.buffer = this.audioContext.createBuffer(1, totalSamples, sampleRate);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async #createNewAudioBuffer(url: string) {
|
|
47
|
+
const time1 = performance.now();
|
|
48
|
+
const response = await fetch(url);
|
|
49
|
+
const time2 = performance.now();
|
|
50
|
+
const encodedSource = await response.arrayBuffer();
|
|
51
|
+
const time3 = performance.now();
|
|
52
|
+
// decodeAudioData() takes about ⅜ - ¾ of a second to decode 4 minutes and 18 seconds of audio.
|
|
53
|
+
const sourceBuffer = await this.audioContext.decodeAudioData(encodedSource);
|
|
54
|
+
const time4 = performance.now();
|
|
55
|
+
const fileSizeKB = encodedSource.byteLength / 1024;
|
|
56
|
+
false &&
|
|
57
|
+
console.log(
|
|
58
|
+
`[audio] fetch: ${(time2 - time1).toFixed(0)} ms (${fileSizeKB.toFixed(0)} KB, ` +
|
|
59
|
+
`${((time2 - time1) / fileSizeKB).toFixed(3)} ms/KB) | ` +
|
|
60
|
+
`arrayBuffer: ${(time3 - time2).toFixed(0)} ms | ` +
|
|
61
|
+
`decode: ${(time4 - time3).toFixed(0)} ms`,
|
|
62
|
+
);
|
|
63
|
+
return sourceBuffer;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
readonly #cache = new Map<string, Promise<AudioBuffer>>();
|
|
67
|
+
readonly #resolved = new Map<string, AudioBuffer>();
|
|
68
|
+
|
|
69
|
+
clearCache() {
|
|
70
|
+
this.#cache.clear();
|
|
71
|
+
this.#resolved.clear();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
warmCache(url: string) {
|
|
75
|
+
this.#findAudioBuffer(url);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Returns the decoded buffer synchronously if already cached, otherwise null. */
|
|
79
|
+
getDecodedBuffer(url: string): AudioBuffer | null {
|
|
80
|
+
return this.#resolved.get(url) ?? null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
#findAudioBuffer(url: string): Promise<AudioBuffer> {
|
|
84
|
+
return this.#cache.getOrInsertComputed(url, (missingUrl) =>
|
|
85
|
+
this.#createNewAudioBuffer(missingUrl).then((buf) => {
|
|
86
|
+
this.#resolved.set(missingUrl, buf);
|
|
87
|
+
return buf;
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Add a new clip to the soundtrack.
|
|
94
|
+
* It is mixed with (added to) any sounds already at that position.
|
|
95
|
+
*
|
|
96
|
+
* The sum can go past ±1, which clips. That's fine for what this is used
|
|
97
|
+
* for, a voiceover with the occasional overlap; the WAV encoder clamps, and
|
|
98
|
+
* live playback clips the same way.
|
|
99
|
+
* @param url Where to find the file.
|
|
100
|
+
*
|
|
101
|
+
* I typically use vite dev mode to run my project.
|
|
102
|
+
* I put the files in the `/public` directory of the project.
|
|
103
|
+
* And the url will start with "./".
|
|
104
|
+
*
|
|
105
|
+
* CORS can be an issue depending on the server.
|
|
106
|
+
* Local files are forbidden.
|
|
107
|
+
* @param startMsInDestination 0 to play the new clip at the the beginning of the video.
|
|
108
|
+
* 1000 to start this clip 1 second after the video starts.
|
|
109
|
+
*
|
|
110
|
+
* Negative numbers are allowed: the part of the clip that would play before
|
|
111
|
+
* the video starts is skipped. A sound clip may legally start before the
|
|
112
|
+
* component that owns it, and that component may be at the very start.
|
|
113
|
+
* @param trimFromStartMs Where to start the clip.
|
|
114
|
+
* 0 to play the entire clip.
|
|
115
|
+
* 500 to trim the first half second from the clip.
|
|
116
|
+
* The default is 0.
|
|
117
|
+
*
|
|
118
|
+
* Negative numbers mean silence before the clip starts: -500 starts the
|
|
119
|
+
* clip half a second after `startMsInDestination`.
|
|
120
|
+
*
|
|
121
|
+
* If you fast forward the resulting video to `startMsInDestination` in your video player,
|
|
122
|
+
* and you fast forward the initial clip in another player to `trimFromStartMs`,
|
|
123
|
+
* and you hit play in both at the same time,
|
|
124
|
+
* they'd play the same thing.
|
|
125
|
+
*
|
|
126
|
+
* **Video files and edit lists**: `decodeAudioData()` ignores the MP4/MOV container's
|
|
127
|
+
* edit list. If the source is a video file (e.g. a Mac screen recording), the audio
|
|
128
|
+
* samples start at media-time 0, but the *presentation* timeline may start later.
|
|
129
|
+
* The caller is responsible for computing the offset from
|
|
130
|
+
* `InputTrack.getFirstTimestamp()` (Mediabunny) and adding it to `trimFromStartMs`
|
|
131
|
+
* so the audio aligns with the video's visible frames.
|
|
132
|
+
* See `development-plans/import-audio-button.md` for the full plan.
|
|
133
|
+
* @param length How much of this clip to include.
|
|
134
|
+
* Stop copying this many milliseconds after `trimFromStartMs`.
|
|
135
|
+
*
|
|
136
|
+
* This value will be clamped to a reasonable range.
|
|
137
|
+
* Requesting 0 or fewer milliseconds means to copy nothing.
|
|
138
|
+
* We stop copying when we get to this much time,
|
|
139
|
+
* the end of the source, or the end of the destination,
|
|
140
|
+
* whichever comes first.
|
|
141
|
+
*
|
|
142
|
+
* The default is `Infinity`, to copy the entire clip or as much as will fit.
|
|
143
|
+
* @returns This promise will resolve (or reject) when the request is complete.
|
|
144
|
+
*/
|
|
145
|
+
async add(
|
|
146
|
+
url: string,
|
|
147
|
+
startMsInDestination: number,
|
|
148
|
+
trimFromStartMs: number = 0,
|
|
149
|
+
length: number = Infinity,
|
|
150
|
+
): Promise<void> {
|
|
151
|
+
if (startMsInDestination < 0) {
|
|
152
|
+
// Skip the part that would play before the video starts.
|
|
153
|
+
trimFromStartMs -= startMsInDestination;
|
|
154
|
+
length += startMsInDestination;
|
|
155
|
+
startMsInDestination = 0;
|
|
156
|
+
}
|
|
157
|
+
if (trimFromStartMs < 0) {
|
|
158
|
+
// Nothing to play before the source starts: start later instead.
|
|
159
|
+
startMsInDestination -= trimFromStartMs;
|
|
160
|
+
length += trimFromStartMs;
|
|
161
|
+
trimFromStartMs = 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const sourceBuffer = await this.#findAudioBuffer(url);
|
|
165
|
+
|
|
166
|
+
const samplesPerMs = this.buffer.sampleRate / 1000;
|
|
167
|
+
const destinationStart = Math.floor(startMsInDestination * samplesPerMs);
|
|
168
|
+
const sourceStart = Math.floor(trimFromStartMs * samplesPerMs);
|
|
169
|
+
// Stop at whichever runs out first: the requested length, the source, or
|
|
170
|
+
// the destination. (decodeAudioData() already resampled the source to
|
|
171
|
+
// our sample rate, so one count works for both.)
|
|
172
|
+
const count = Math.max(
|
|
173
|
+
0,
|
|
174
|
+
Math.min(
|
|
175
|
+
Math.floor(length * samplesPerMs),
|
|
176
|
+
sourceBuffer.length - sourceStart,
|
|
177
|
+
this.buffer.length - destinationStart,
|
|
178
|
+
),
|
|
179
|
+
);
|
|
180
|
+
if (count === 0) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const destination = this.buffer
|
|
184
|
+
.getChannelData(0)
|
|
185
|
+
.subarray(destinationStart, destinationStart + count);
|
|
186
|
+
const channels = Array.from(
|
|
187
|
+
{ length: sourceBuffer.numberOfChannels },
|
|
188
|
+
(_, channel) =>
|
|
189
|
+
sourceBuffer
|
|
190
|
+
.getChannelData(channel)
|
|
191
|
+
.subarray(sourceStart, sourceStart + count),
|
|
192
|
+
);
|
|
193
|
+
if (channels.length === 1) {
|
|
194
|
+
// The common case.
|
|
195
|
+
const source = channels[0];
|
|
196
|
+
for (let i = 0; i < count; i++) {
|
|
197
|
+
destination[i] += source[i];
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
// Average the channels, don't sum them: identical channels (the usual
|
|
201
|
+
// "stereo") come out exactly as they went in, where a sum would double
|
|
202
|
+
// the level and clip.
|
|
203
|
+
const scale = 1 / channels.length;
|
|
204
|
+
for (let i = 0; i < count; i++) {
|
|
205
|
+
let sum = 0;
|
|
206
|
+
for (const channel of channels) {
|
|
207
|
+
sum += channel[i];
|
|
208
|
+
}
|
|
209
|
+
destination[i] += sum * scale;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async toBlob(): Promise<Blob> {
|
|
215
|
+
const wavArrayBuffer = this.audioBufferToWav(this.buffer);
|
|
216
|
+
return new Blob([wavArrayBuffer], { type: "audio/wav" });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async assignToAudioElement(audioElement: HTMLAudioElement): Promise<void> {
|
|
220
|
+
const blob = await this.toBlob();
|
|
221
|
+
audioElement.src = URL.createObjectURL(blob);
|
|
222
|
+
// Optional: audioElement.load();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Simple 16-bit PCM WAV encoder
|
|
226
|
+
// This takes about 0.6 seconds to save 8½ minutes of data.
|
|
227
|
+
private audioBufferToWav(buffer: AudioBuffer): ArrayBuffer {
|
|
228
|
+
console.log("audioBufferToWav()");
|
|
229
|
+
const numChannels = buffer.numberOfChannels;
|
|
230
|
+
const sampleRate = buffer.sampleRate;
|
|
231
|
+
const length = buffer.length * numChannels * 2 + 44;
|
|
232
|
+
const arrayBuffer = new ArrayBuffer(length);
|
|
233
|
+
const view = new DataView(arrayBuffer);
|
|
234
|
+
|
|
235
|
+
const writeString = (offset: number, str: string) => {
|
|
236
|
+
for (let i = 0; i < str.length; i++)
|
|
237
|
+
view.setUint8(offset + i, str.charCodeAt(i));
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
writeString(0, "RIFF");
|
|
241
|
+
view.setUint32(4, 36 + buffer.length * numChannels * 2, true);
|
|
242
|
+
writeString(8, "WAVE");
|
|
243
|
+
writeString(12, "fmt ");
|
|
244
|
+
view.setUint32(16, 16, true);
|
|
245
|
+
view.setUint16(20, 1, true);
|
|
246
|
+
view.setUint16(22, numChannels, true);
|
|
247
|
+
view.setUint32(24, sampleRate, true);
|
|
248
|
+
view.setUint32(28, sampleRate * numChannels * 2, true);
|
|
249
|
+
view.setUint16(32, numChannels * 2, true);
|
|
250
|
+
view.setUint16(34, 16, true);
|
|
251
|
+
writeString(36, "data");
|
|
252
|
+
view.setUint32(40, buffer.length * numChannels * 2, true);
|
|
253
|
+
|
|
254
|
+
let offset = 44;
|
|
255
|
+
for (let ch = 0; ch < numChannels; ch++) {
|
|
256
|
+
console.log("Wuz lots!");
|
|
257
|
+
const channel = buffer.getChannelData(ch);
|
|
258
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
259
|
+
const sample = Math.max(-1, Math.min(1, channel[i]));
|
|
260
|
+
view.setInt16(
|
|
261
|
+
offset,
|
|
262
|
+
sample < 0 ? sample * 0x8000 : sample * 0x7fff,
|
|
263
|
+
true,
|
|
264
|
+
);
|
|
265
|
+
offset += 2;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return arrayBuffer;
|
|
270
|
+
}
|
|
271
|
+
}
|