@omnimedia/omnitool 1.1.0-5 → 1.1.0-51

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.
Files changed (380) hide show
  1. package/README.md +143 -80
  2. package/package.json +18 -16
  3. package/s/context.ts +0 -7
  4. package/s/demo/demo.bundle.ts +102 -43
  5. package/s/demo/demo.css +246 -11
  6. package/s/demo/routines/export-test.ts +16 -0
  7. package/s/demo/routines/filmstrip-test.ts +22 -18
  8. package/s/demo/routines/load-video.ts +2 -3
  9. package/s/demo/routines/playback-test.ts +76 -0
  10. package/s/demo/routines/timeline-setup.ts +24 -0
  11. package/s/demo/routines/transcode-test.ts +21 -5
  12. package/s/demo/routines/transitions-test.ts +2 -2
  13. package/s/demo/routines/waveform-test.ts +8 -6
  14. package/s/driver/driver-worker.ts +9 -0
  15. package/s/driver/driver.test.ts +1 -1
  16. package/s/driver/driver.ts +32 -44
  17. package/s/driver/fns/schematic.ts +52 -25
  18. package/s/driver/fns/work.ts +71 -200
  19. package/s/driver/parts/compositor.ts +178 -0
  20. package/s/driver/parts/machina.ts +19 -20
  21. package/s/index.html.ts +103 -19
  22. package/s/index.ts +1 -0
  23. package/s/tests.bundle.ts +11 -0
  24. package/s/tests.html.ts +28 -0
  25. package/s/timeline/index.ts +3 -0
  26. package/s/timeline/parts/basics.ts +1 -1
  27. package/s/timeline/parts/filmstrip.ts +43 -16
  28. package/s/timeline/parts/item.ts +59 -6
  29. package/s/timeline/parts/media.ts +32 -1
  30. package/s/timeline/parts/resource-pool.ts +8 -5
  31. package/s/timeline/parts/resource.ts +2 -0
  32. package/s/timeline/parts/waveform.ts +3 -4
  33. package/s/timeline/renderers/export/parts/audio-gain.ts +17 -0
  34. package/s/timeline/renderers/export/parts/audio-mix.ts +133 -0
  35. package/s/timeline/renderers/export/parts/cursor.ts +109 -0
  36. package/s/timeline/renderers/export/parts/produce-audio.ts +64 -0
  37. package/s/timeline/renderers/export/parts/produce-video.ts +50 -0
  38. package/s/timeline/renderers/export/parts/resamplers.ts +48 -0
  39. package/s/timeline/renderers/export/produce.ts +28 -0
  40. package/s/timeline/renderers/parts/handy.ts +360 -0
  41. package/s/timeline/renderers/parts/samplers/audio/parts/find.ts +19 -0
  42. package/s/timeline/renderers/parts/samplers/audio/parts/init.ts +60 -0
  43. package/s/timeline/renderers/parts/samplers/audio/parts/sink.ts +38 -0
  44. package/s/timeline/renderers/parts/samplers/audio/parts/types.ts +16 -0
  45. package/s/timeline/renderers/parts/samplers/audio/sampler.ts +35 -0
  46. package/s/timeline/renderers/parts/samplers/visual/parts/defaults.ts +16 -0
  47. package/s/timeline/renderers/parts/samplers/visual/parts/sample.ts +59 -0
  48. package/s/timeline/renderers/parts/samplers/visual/parts/sequence.ts +111 -0
  49. package/s/timeline/renderers/parts/samplers/visual/parts/sink.ts +38 -0
  50. package/s/timeline/renderers/parts/samplers/visual/parts/transition.ts +28 -0
  51. package/s/timeline/renderers/parts/samplers/visual/parts/types.ts +10 -0
  52. package/s/timeline/renderers/parts/samplers/visual/sampler.ts +28 -0
  53. package/s/timeline/renderers/parts/schedulers.ts +96 -0
  54. package/s/timeline/renderers/player/parts/playback.ts +125 -0
  55. package/s/timeline/renderers/player/player.ts +71 -0
  56. package/s/timeline/renderers/renderers.test.ts +387 -0
  57. package/s/timeline/sugar/helpers.ts +85 -0
  58. package/s/timeline/sugar/o.ts +178 -38
  59. package/s/timeline/sugar/omni.test.ts +210 -0
  60. package/s/timeline/sugar/omni.ts +38 -12
  61. package/s/timeline/types.ts +29 -0
  62. package/s/timeline/utils/checksum.ts +3 -1
  63. package/s/timeline/utils/datafile.ts +15 -4
  64. package/s/timeline/utils/dummy-data.ts +3 -3
  65. package/s/timeline/utils/matrix.ts +33 -0
  66. package/s/units/fps.ts +8 -0
  67. package/s/units/ms.ts +8 -0
  68. package/s/units/seconds.ts +8 -0
  69. package/x/WebGLRenderer-7X274AYV.js +2 -0
  70. package/x/WebGLRenderer-7X274AYV.js.map +7 -0
  71. package/x/WebGPURenderer-XMCMEXAO.js +2 -0
  72. package/x/WebGPURenderer-XMCMEXAO.js.map +7 -0
  73. package/x/browserAll-6TVTCHHE.js +2 -0
  74. package/x/browserAll-6TVTCHHE.js.map +7 -0
  75. package/x/chunk-4ONWQOPX.js +157 -0
  76. package/x/chunk-4ONWQOPX.js.map +7 -0
  77. package/x/chunk-63NSCXPX.js +2 -0
  78. package/x/chunk-63NSCXPX.js.map +7 -0
  79. package/x/chunk-A45M2HJC.js +2 -0
  80. package/x/chunk-A45M2HJC.js.map +7 -0
  81. package/x/chunk-OTQK6FAJ.js +15 -0
  82. package/x/chunk-OTQK6FAJ.js.map +7 -0
  83. package/x/chunk-Q7JBQNE4.js +42 -0
  84. package/x/chunk-Q7JBQNE4.js.map +7 -0
  85. package/x/chunk-W33LM336.js +393 -0
  86. package/x/chunk-W33LM336.js.map +7 -0
  87. package/x/chunk-W5CN46AR.js +327 -0
  88. package/x/chunk-W5CN46AR.js.map +7 -0
  89. package/x/chunk-WFT3KTZG.js +269 -0
  90. package/x/chunk-WFT3KTZG.js.map +7 -0
  91. package/x/context.d.ts +1 -4
  92. package/x/context.js +1 -5
  93. package/x/context.js.map +1 -1
  94. package/x/demo/WebGLRenderer-NLGJGAXK.js +2 -0
  95. package/x/demo/WebGLRenderer-NLGJGAXK.js.map +7 -0
  96. package/x/demo/WebGPURenderer-RBOFXPL5.js +2 -0
  97. package/x/demo/WebGPURenderer-RBOFXPL5.js.map +7 -0
  98. package/x/demo/browserAll-5AZHDDG6.js +2 -0
  99. package/x/demo/browserAll-5AZHDDG6.js.map +7 -0
  100. package/x/demo/chunk-5ZZYIILO.js +393 -0
  101. package/x/demo/chunk-5ZZYIILO.js.map +7 -0
  102. package/x/demo/chunk-P3PTHHFE.js +42 -0
  103. package/x/demo/chunk-P3PTHHFE.js.map +7 -0
  104. package/x/demo/chunk-PYG4RZZ2.js +269 -0
  105. package/x/demo/chunk-PYG4RZZ2.js.map +7 -0
  106. package/x/demo/chunk-Q4MWBZHL.js +157 -0
  107. package/x/demo/chunk-Q4MWBZHL.js.map +7 -0
  108. package/x/demo/chunk-T3METYEY.js +15 -0
  109. package/x/demo/chunk-T3METYEY.js.map +7 -0
  110. package/x/demo/chunk-USLRKDKD.js +2 -0
  111. package/x/demo/chunk-USLRKDKD.js.map +7 -0
  112. package/x/demo/chunk-YISSXWBT.js +327 -0
  113. package/x/demo/chunk-YISSXWBT.js.map +7 -0
  114. package/x/demo/chunk-YJQWVIHX.js +2 -0
  115. package/x/demo/chunk-YJQWVIHX.js.map +7 -0
  116. package/x/demo/demo.bundle.js +92 -40
  117. package/x/demo/demo.bundle.js.map +1 -1
  118. package/x/demo/demo.bundle.min.js +2450 -35
  119. package/x/demo/demo.bundle.min.js.map +4 -4
  120. package/x/demo/demo.css +246 -11
  121. package/x/demo/routines/export-test.d.ts +2 -0
  122. package/x/demo/routines/export-test.js +10 -0
  123. package/x/demo/routines/export-test.js.map +1 -0
  124. package/x/demo/routines/filmstrip-test.d.ts +1 -1
  125. package/x/demo/routines/filmstrip-test.js +20 -17
  126. package/x/demo/routines/filmstrip-test.js.map +1 -1
  127. package/x/demo/routines/load-video.d.ts +1 -1
  128. package/x/demo/routines/load-video.js +1 -2
  129. package/x/demo/routines/load-video.js.map +1 -1
  130. package/x/demo/routines/playback-test.d.ts +2 -0
  131. package/x/demo/routines/playback-test.js +65 -0
  132. package/x/demo/routines/playback-test.js.map +1 -0
  133. package/x/demo/routines/timeline-setup.d.ts +6 -0
  134. package/x/demo/routines/timeline-setup.js +13 -0
  135. package/x/demo/routines/timeline-setup.js.map +1 -0
  136. package/x/demo/routines/transcode-test.js +17 -5
  137. package/x/demo/routines/transcode-test.js.map +1 -1
  138. package/x/demo/routines/transitions-test.js +2 -2
  139. package/x/demo/routines/transitions-test.js.map +1 -1
  140. package/x/demo/routines/waveform-test.d.ts +2 -1
  141. package/x/demo/routines/waveform-test.js +7 -6
  142. package/x/demo/routines/waveform-test.js.map +1 -1
  143. package/x/demo/webworkerAll-QKIC5O27.js +2 -0
  144. package/x/demo/webworkerAll-QKIC5O27.js.map +7 -0
  145. package/x/driver/WebGLRenderer-OMRWYQIV.js +2 -0
  146. package/x/driver/WebGLRenderer-OMRWYQIV.js.map +7 -0
  147. package/x/driver/WebGPURenderer-KQJB2OJJ.js +2 -0
  148. package/x/driver/WebGPURenderer-KQJB2OJJ.js.map +7 -0
  149. package/x/driver/browserAll-YBZEJCN3.js +2 -0
  150. package/x/driver/browserAll-YBZEJCN3.js.map +7 -0
  151. package/x/driver/chunk-3L3MB5NY.js +393 -0
  152. package/x/driver/chunk-3L3MB5NY.js.map +7 -0
  153. package/x/driver/chunk-42BQ4XKE.js +269 -0
  154. package/x/driver/chunk-42BQ4XKE.js.map +7 -0
  155. package/x/driver/chunk-4HAYG3N5.js +327 -0
  156. package/x/driver/chunk-4HAYG3N5.js.map +7 -0
  157. package/x/driver/chunk-BFBY7VYB.js +42 -0
  158. package/x/driver/chunk-BFBY7VYB.js.map +7 -0
  159. package/x/driver/chunk-KM6O72WE.js +157 -0
  160. package/x/driver/chunk-KM6O72WE.js.map +7 -0
  161. package/x/driver/chunk-N6HD4WYJ.js +2 -0
  162. package/x/driver/chunk-N6HD4WYJ.js.map +7 -0
  163. package/x/driver/chunk-WCZ2O3UN.js +15 -0
  164. package/x/driver/chunk-WCZ2O3UN.js.map +7 -0
  165. package/x/driver/chunk-XWNSF3WJ.js +2 -0
  166. package/x/driver/chunk-XWNSF3WJ.js.map +7 -0
  167. package/x/driver/driver-worker.d.ts +1 -0
  168. package/x/driver/driver-worker.js +6 -0
  169. package/x/driver/driver-worker.js.map +1 -0
  170. package/x/driver/driver.d.ts +12 -9
  171. package/x/driver/driver.js +31 -41
  172. package/x/driver/driver.js.map +1 -1
  173. package/x/driver/driver.test.js +1 -1
  174. package/x/driver/driver.test.js.map +1 -1
  175. package/x/driver/driver.worker.bundle.min.js +139 -1135
  176. package/x/driver/driver.worker.bundle.min.js.map +4 -4
  177. package/x/driver/fns/host.d.ts +10 -4
  178. package/x/driver/fns/schematic.d.ts +47 -24
  179. package/x/driver/fns/work.d.ts +12 -7
  180. package/x/driver/fns/work.js +68 -170
  181. package/x/driver/fns/work.js.map +1 -1
  182. package/x/driver/parts/compositor.d.ts +15 -0
  183. package/x/driver/parts/compositor.js +152 -0
  184. package/x/driver/parts/compositor.js.map +1 -0
  185. package/x/driver/parts/machina.d.ts +0 -20
  186. package/x/driver/parts/machina.js +6 -10
  187. package/x/driver/parts/machina.js.map +1 -1
  188. package/x/driver/webworkerAll-BKJQW6P7.js +2 -0
  189. package/x/driver/webworkerAll-BKJQW6P7.js.map +7 -0
  190. package/x/features/speech/transcribe/parts/prep-audio.d.ts +1 -1
  191. package/x/features/speech/transcribe/worker.bundle.min.js +703 -703
  192. package/x/features/speech/transcribe/worker.bundle.min.js.map +4 -4
  193. package/x/index.d.ts +1 -0
  194. package/x/index.html +349 -30
  195. package/x/index.html.js +103 -19
  196. package/x/index.html.js.map +1 -1
  197. package/x/index.js +1 -0
  198. package/x/index.js.map +1 -1
  199. package/x/tests.bundle.js +8 -0
  200. package/x/tests.bundle.js.map +1 -0
  201. package/x/tests.bundle.min.js +2464 -0
  202. package/x/tests.bundle.min.js.map +7 -0
  203. package/x/tests.html +316 -0
  204. package/x/tests.html.d.ts +2 -0
  205. package/x/tests.html.js +22 -0
  206. package/x/tests.html.js.map +1 -0
  207. package/x/timeline/index.d.ts +3 -0
  208. package/x/timeline/index.js +3 -0
  209. package/x/timeline/index.js.map +1 -1
  210. package/x/timeline/parts/basics.d.ts +1 -1
  211. package/x/timeline/parts/filmstrip.d.ts +4 -3
  212. package/x/timeline/parts/filmstrip.js +29 -10
  213. package/x/timeline/parts/filmstrip.js.map +1 -1
  214. package/x/timeline/parts/item.d.ts +51 -8
  215. package/x/timeline/parts/item.js +7 -3
  216. package/x/timeline/parts/item.js.map +1 -1
  217. package/x/timeline/parts/media.d.ts +5 -0
  218. package/x/timeline/parts/media.js +27 -1
  219. package/x/timeline/parts/media.js.map +1 -1
  220. package/x/timeline/parts/resource-pool.d.ts +3 -0
  221. package/x/timeline/parts/resource-pool.js +7 -4
  222. package/x/timeline/parts/resource-pool.js.map +1 -1
  223. package/x/timeline/parts/resource.d.ts +2 -0
  224. package/x/timeline/parts/waveform.d.ts +2 -1
  225. package/x/timeline/parts/waveform.js +2 -4
  226. package/x/timeline/parts/waveform.js.map +1 -1
  227. package/x/timeline/renderers/export/parts/audio-gain.d.ts +1 -0
  228. package/x/timeline/renderers/export/parts/audio-gain.js +13 -0
  229. package/x/timeline/renderers/export/parts/audio-gain.js.map +1 -0
  230. package/x/timeline/renderers/export/parts/audio-mix.d.ts +21 -0
  231. package/x/timeline/renderers/export/parts/audio-mix.js +89 -0
  232. package/x/timeline/renderers/export/parts/audio-mix.js.map +1 -0
  233. package/x/timeline/renderers/export/parts/cursor.d.ts +19 -0
  234. package/x/timeline/renderers/export/parts/cursor.js +80 -0
  235. package/x/timeline/renderers/export/parts/cursor.js.map +1 -0
  236. package/x/timeline/renderers/export/parts/produce-audio.d.ts +6 -0
  237. package/x/timeline/renderers/export/parts/produce-audio.js +41 -0
  238. package/x/timeline/renderers/export/parts/produce-audio.js.map +1 -0
  239. package/x/timeline/renderers/export/parts/produce-video.d.ts +10 -0
  240. package/x/timeline/renderers/export/parts/produce-video.js +27 -0
  241. package/x/timeline/renderers/export/parts/produce-video.js.map +1 -0
  242. package/x/timeline/renderers/export/parts/resamplers.d.ts +12 -0
  243. package/x/timeline/renderers/export/parts/resamplers.js +29 -0
  244. package/x/timeline/renderers/export/parts/resamplers.js.map +1 -0
  245. package/x/timeline/renderers/export/produce.d.ts +13 -0
  246. package/x/timeline/renderers/export/produce.js +15 -0
  247. package/x/timeline/renderers/export/produce.js.map +1 -0
  248. package/x/timeline/renderers/parts/handy.d.ts +30 -0
  249. package/x/timeline/renderers/parts/handy.js +219 -0
  250. package/x/timeline/renderers/parts/handy.js.map +1 -0
  251. package/x/timeline/renderers/parts/samplers/audio/parts/find.d.ts +6 -0
  252. package/x/timeline/renderers/parts/samplers/audio/parts/find.js +15 -0
  253. package/x/timeline/renderers/parts/samplers/audio/parts/find.js.map +1 -0
  254. package/x/timeline/renderers/parts/samplers/audio/parts/init.d.ts +5 -0
  255. package/x/timeline/renderers/parts/samplers/audio/parts/init.js +40 -0
  256. package/x/timeline/renderers/parts/samplers/audio/parts/init.js.map +1 -0
  257. package/x/timeline/renderers/parts/samplers/audio/parts/sink.d.ts +8 -0
  258. package/x/timeline/renderers/parts/samplers/audio/parts/sink.js +24 -0
  259. package/x/timeline/renderers/parts/samplers/audio/parts/sink.js.map +1 -0
  260. package/x/timeline/renderers/parts/samplers/audio/parts/types.d.ts +14 -0
  261. package/x/timeline/renderers/parts/samplers/audio/parts/types.js.map +1 -0
  262. package/x/timeline/renderers/parts/samplers/audio/sampler.d.ts +11 -0
  263. package/x/timeline/renderers/parts/samplers/audio/sampler.js +22 -0
  264. package/x/timeline/renderers/parts/samplers/audio/sampler.js.map +1 -0
  265. package/x/timeline/renderers/parts/samplers/visual/parts/defaults.d.ts +5 -0
  266. package/x/timeline/renderers/parts/samplers/visual/parts/defaults.js +10 -0
  267. package/x/timeline/renderers/parts/samplers/visual/parts/defaults.js.map +1 -0
  268. package/x/timeline/renderers/parts/samplers/visual/parts/sample.d.ts +5 -0
  269. package/x/timeline/renderers/parts/samplers/visual/parts/sample.js +38 -0
  270. package/x/timeline/renderers/parts/samplers/visual/parts/sample.js.map +1 -0
  271. package/x/timeline/renderers/parts/samplers/visual/parts/sequence.d.ts +5 -0
  272. package/x/timeline/renderers/parts/samplers/visual/parts/sequence.js +75 -0
  273. package/x/timeline/renderers/parts/samplers/visual/parts/sequence.js.map +1 -0
  274. package/x/timeline/renderers/parts/samplers/visual/parts/sink.d.ts +8 -0
  275. package/x/timeline/renderers/parts/samplers/visual/parts/sink.js +24 -0
  276. package/x/timeline/renderers/parts/samplers/visual/parts/sink.js.map +1 -0
  277. package/x/timeline/renderers/parts/samplers/visual/parts/transition.d.ts +3 -0
  278. package/x/timeline/renderers/parts/samplers/visual/parts/transition.js +18 -0
  279. package/x/timeline/renderers/parts/samplers/visual/parts/transition.js.map +1 -0
  280. package/x/timeline/renderers/parts/samplers/visual/parts/types.d.ts +8 -0
  281. package/x/timeline/renderers/parts/samplers/visual/parts/types.js +2 -0
  282. package/x/timeline/renderers/parts/samplers/visual/parts/types.js.map +1 -0
  283. package/x/timeline/renderers/parts/samplers/visual/sampler.d.ts +7 -0
  284. package/x/timeline/renderers/parts/samplers/visual/sampler.js +17 -0
  285. package/x/timeline/renderers/parts/samplers/visual/sampler.js.map +1 -0
  286. package/x/timeline/renderers/parts/schedulers.d.ts +17 -0
  287. package/x/timeline/renderers/parts/schedulers.js +64 -0
  288. package/x/timeline/renderers/parts/schedulers.js.map +1 -0
  289. package/x/timeline/renderers/player/parts/playback.d.ts +31 -0
  290. package/x/timeline/renderers/player/parts/playback.js +91 -0
  291. package/x/timeline/renderers/player/parts/playback.js.map +1 -0
  292. package/x/timeline/renderers/player/player.d.ts +23 -0
  293. package/x/timeline/renderers/player/player.js +50 -0
  294. package/x/timeline/renderers/player/player.js.map +1 -0
  295. package/x/timeline/renderers/renderers.test.d.ts +32 -0
  296. package/x/timeline/renderers/renderers.test.js +306 -0
  297. package/x/timeline/renderers/renderers.test.js.map +1 -0
  298. package/x/timeline/sugar/helpers.d.ts +30 -0
  299. package/x/timeline/sugar/helpers.js +46 -0
  300. package/x/timeline/sugar/helpers.js.map +1 -0
  301. package/x/timeline/sugar/o.d.ts +31 -4
  302. package/x/timeline/sugar/o.js +144 -38
  303. package/x/timeline/sugar/o.js.map +1 -1
  304. package/x/timeline/sugar/omni.d.ts +11 -2
  305. package/x/timeline/sugar/omni.js +30 -9
  306. package/x/timeline/sugar/omni.js.map +1 -1
  307. package/x/timeline/sugar/omni.test.d.ts +27 -0
  308. package/x/timeline/sugar/omni.test.js +128 -0
  309. package/x/timeline/sugar/omni.test.js.map +1 -0
  310. package/x/timeline/types.d.ts +24 -0
  311. package/x/timeline/types.js +2 -0
  312. package/x/timeline/types.js.map +1 -0
  313. package/x/timeline/utils/checksum.d.ts +3 -2
  314. package/x/timeline/utils/checksum.js.map +1 -1
  315. package/x/timeline/utils/datafile.d.ts +5 -3
  316. package/x/timeline/utils/datafile.js +18 -5
  317. package/x/timeline/utils/datafile.js.map +1 -1
  318. package/x/timeline/utils/dummy-data.d.ts +1 -2
  319. package/x/timeline/utils/dummy-data.js +4 -2
  320. package/x/timeline/utils/dummy-data.js.map +1 -1
  321. package/x/timeline/utils/matrix.d.ts +8 -0
  322. package/x/timeline/utils/matrix.js +26 -0
  323. package/x/timeline/utils/matrix.js.map +1 -0
  324. package/x/units/fps.d.ts +6 -0
  325. package/x/units/fps.js +2 -0
  326. package/x/units/fps.js.map +1 -0
  327. package/x/units/ms.d.ts +6 -0
  328. package/x/units/ms.js +2 -0
  329. package/x/units/ms.js.map +1 -0
  330. package/x/units/seconds.d.ts +6 -0
  331. package/x/units/seconds.js +2 -0
  332. package/x/units/seconds.js.map +1 -0
  333. package/x/webworkerAll-VVIU3M54.js +2 -0
  334. package/x/webworkerAll-VVIU3M54.js.map +7 -0
  335. package/s/tests.test.ts +0 -8
  336. package/s/timeline/sugar/omni-test.ts +0 -38
  337. package/s/tools/common/loader.ts +0 -26
  338. package/s/tools/common/transformer-pipeline.ts +0 -26
  339. package/s/tools/speech-recognition/common/model.ts +0 -26
  340. package/s/tools/speech-recognition/whisper/fns/host.ts +0 -25
  341. package/s/tools/speech-recognition/whisper/fns/schematic.ts +0 -23
  342. package/s/tools/speech-recognition/whisper/fns/work.ts +0 -91
  343. package/s/tools/speech-recognition/whisper/parts/types.ts +0 -38
  344. package/s/tools/speech-recognition/whisper/parts/worker.bundle.ts +0 -7
  345. package/s/tools/speech-recognition/whisper/tool.ts +0 -70
  346. package/x/tests.test.js +0 -6
  347. package/x/tests.test.js.map +0 -1
  348. package/x/timeline/sugar/omni-test.d.ts +0 -1
  349. package/x/timeline/sugar/omni-test.js +0 -22
  350. package/x/timeline/sugar/omni-test.js.map +0 -1
  351. package/x/tools/common/loader.d.ts +0 -19
  352. package/x/tools/common/loader.js +0 -18
  353. package/x/tools/common/loader.js.map +0 -1
  354. package/x/tools/common/transformer-pipeline.d.ts +0 -8
  355. package/x/tools/common/transformer-pipeline.js +0 -24
  356. package/x/tools/common/transformer-pipeline.js.map +0 -1
  357. package/x/tools/speech-recognition/common/model.d.ts +0 -14
  358. package/x/tools/speech-recognition/common/model.js +0 -16
  359. package/x/tools/speech-recognition/common/model.js.map +0 -1
  360. package/x/tools/speech-recognition/whisper/fns/host.d.ts +0 -13
  361. package/x/tools/speech-recognition/whisper/fns/host.js +0 -19
  362. package/x/tools/speech-recognition/whisper/fns/host.js.map +0 -1
  363. package/x/tools/speech-recognition/whisper/fns/schematic.d.ts +0 -19
  364. package/x/tools/speech-recognition/whisper/fns/schematic.js +0 -2
  365. package/x/tools/speech-recognition/whisper/fns/schematic.js.map +0 -1
  366. package/x/tools/speech-recognition/whisper/fns/work.d.ts +0 -12
  367. package/x/tools/speech-recognition/whisper/fns/work.js +0 -74
  368. package/x/tools/speech-recognition/whisper/fns/work.js.map +0 -1
  369. package/x/tools/speech-recognition/whisper/parts/types.d.ts +0 -31
  370. package/x/tools/speech-recognition/whisper/parts/types.js.map +0 -1
  371. package/x/tools/speech-recognition/whisper/parts/worker.bundle.d.ts +0 -1
  372. package/x/tools/speech-recognition/whisper/parts/worker.bundle.js +0 -4
  373. package/x/tools/speech-recognition/whisper/parts/worker.bundle.js.map +0 -1
  374. package/x/tools/speech-recognition/whisper/parts/worker.bundle.min.js +0 -8
  375. package/x/tools/speech-recognition/whisper/parts/worker.bundle.min.js.map +0 -7
  376. package/x/tools/speech-recognition/whisper/tool.d.ts +0 -12
  377. package/x/tools/speech-recognition/whisper/tool.js +0 -63
  378. package/x/tools/speech-recognition/whisper/tool.js.map +0 -1
  379. /package/x/{tests.test.d.ts → tests.bundle.d.ts} +0 -0
  380. /package/x/{tools/speech-recognition/whisper → timeline/renderers/parts/samplers/audio}/parts/types.js +0 -0
@@ -0,0 +1,387 @@
1
+
2
+ import {Science, test, expect} from "@e280/science"
3
+
4
+ import {O} from "../sugar/o.js"
5
+ import {ms} from "../../units/ms.js"
6
+ import {Omni} from "../sugar/omni.js"
7
+ import {fps} from "../../units/fps.js"
8
+ import {Datafile} from "../utils/datafile.js"
9
+ import {Driver} from "../../driver/driver.js"
10
+ import {AudioMix} from "./export/parts/audio-mix.js"
11
+ import {produceAudio} from "./export/parts/produce-audio.js"
12
+ import {resampleToPlanar} from "./export/parts/resamplers.js"
13
+ import {loadVideo} from "../../demo/routines/load-video.js"
14
+ import {produceVideo} from "./export/parts/produce-video.js"
15
+ import {CursorVisualSampler} from "./export/parts/cursor.js"
16
+ import {applyGainToPlanar} from "./export/parts/audio-gain.js"
17
+ import {createVisualSampler} from "./parts/samplers/visual/sampler.js"
18
+
19
+ const workerUrl = new URL("../driver/driver.worker.bundle.min.js", import.meta.url)
20
+ export async function setupTest() {
21
+ const driver = await Driver.setup({workerUrl})
22
+ const omni = new Omni(driver)
23
+
24
+ const testVideo = await loadVideo("/assets/temp/test.mp4")
25
+ const {videoA} = await omni.load({videoA: Datafile.make(testVideo, "test.mp4")})
26
+
27
+ const resolveMedia = (hash: string) => omni.resources.require(hash).blob
28
+
29
+ return {driver, omni, testVideo, videoA, resolveMedia}
30
+ }
31
+
32
+ async function collect<T>(iterable: AsyncIterable<T>) {
33
+ const out: T[] = []
34
+ for await (const item of iterable)
35
+ out.push(item)
36
+ return out
37
+ }
38
+
39
+ const near = (actual: number, expected: number, eps = 1e-6) =>
40
+ Math.abs(actual - expected) < eps
41
+
42
+ export default Science.suite({
43
+
44
+ "cursor visual sampler cannot get previous samples": test(async () => {
45
+ const {omni, videoA, resolveMedia, driver} = await setupTest()
46
+ const {timeline} = new O({timeline: omni.timeline(o => o.sequence(
47
+ o.video(videoA, {duration: 2000}),
48
+ o.gap(500),
49
+ o.video(videoA, {duration: 2000}),
50
+ o.audio(videoA, {duration: 500}),
51
+ ))})
52
+ const sampler = new CursorVisualSampler(driver, resolveMedia)
53
+ const cursor = sampler.cursor(timeline)
54
+ await cursor.next(ms(1000))
55
+ await expect(async () => await cursor.next(ms(100))).throwsAsync()
56
+ }),
57
+
58
+ "visual sampler gives correct layer at x time": test(async () => {
59
+ const {omni, videoA, resolveMedia} = await setupTest()
60
+ const {timeline} = new O({timeline: omni.timeline(o => o.sequence(
61
+ o.video(videoA, {duration: 2000}),
62
+ o.gap(500),
63
+ o.video(videoA, {duration: 2000}),
64
+ o.audio(videoA, {duration: 500}),
65
+ o.text("123", {duration: 1000})
66
+ ))})
67
+ const sampler = createVisualSampler(resolveMedia)
68
+ const imgLayer = await sampler.sample(timeline, ms(1000))
69
+ expect(imgLayer[0].kind).is("image")
70
+ const gapLayer = await sampler.sample(timeline, ms(2300))
71
+ expect(gapLayer[0].kind).is("gap")
72
+ const imgLayer1 = await sampler.sample(timeline, ms(2700))
73
+ expect(imgLayer1[0].kind).is("image")
74
+ const textLayer = await sampler.sample(timeline, ms(5500))
75
+ expect(textLayer[0].kind).is("text")
76
+ }),
77
+
78
+ "audio mix sums overlapping chunks": test(async () => {
79
+ const mixer = new AudioMix({chunkFrames: 4, clamp: false})
80
+ async function *samples() {
81
+ yield {
82
+ planes: [new Float32Array([0.25, 0.25, 0.25, 0.25])],
83
+ sampleRate: 4,
84
+ timestamp: 0
85
+ }
86
+ yield {
87
+ planes: [new Float32Array([0.5, 0.5, 0.5, 0.5])],
88
+ sampleRate: 4,
89
+ timestamp: 0.5
90
+ }
91
+ }
92
+
93
+ const mixed = await collect(mixer.mix(samples()))
94
+ expect(mixed.length).is(2)
95
+ expect(mixed[0].startFrame).is(0)
96
+ expect(mixed[0].frames).is(4)
97
+ expect(mixed[0].channels).is(1)
98
+ expect(mixed[0].planar[0]).is(0.25)
99
+ expect(mixed[0].planar[1]).is(0.25)
100
+ expect(mixed[0].planar[2]).is(0.75)
101
+ expect(mixed[0].planar[3]).is(0.75)
102
+ expect(mixed[1].startFrame).is(4)
103
+ expect(mixed[1].planar[0]).is(0.5)
104
+ expect(mixed[1].planar[1]).is(0.5)
105
+ expect(mixed[1].planar[2]).is(0)
106
+ expect(mixed[1].planar[3]).is(0)
107
+ }),
108
+
109
+ "audio mix clamps output to [-1, 1]": test(async () => {
110
+ const mixer = new AudioMix({chunkFrames: 4, clamp: true})
111
+ async function *samples() {
112
+ yield {
113
+ planes: [new Float32Array([0.9, 0.9, 0.9, 0.9])],
114
+ sampleRate: 4,
115
+ timestamp: 0
116
+ }
117
+ yield {
118
+ planes: [new Float32Array([0.8, 0.8, 0.8, 0.8])],
119
+ sampleRate: 4,
120
+ timestamp: 0
121
+ }
122
+ }
123
+
124
+ const mixed = await collect(mixer.mix(samples()))
125
+ expect(mixed.length).is(1)
126
+ expect(mixed[0].planar[0]).is(1)
127
+ expect(mixed[0].planar[1]).is(1)
128
+ expect(mixed[0].planar[2]).is(1)
129
+ expect(mixed[0].planar[3]).is(1)
130
+ }),
131
+
132
+ "audio mix fills gaps with silence": test(async () => {
133
+ const mixer = new AudioMix({chunkFrames: 4, clamp: false})
134
+ async function *samples() {
135
+ yield {
136
+ planes: [new Float32Array([1, 1, 1, 1])],
137
+ sampleRate: 4,
138
+ timestamp: 0
139
+ }
140
+ yield {
141
+ planes: [new Float32Array([2, 2, 2, 2])],
142
+ sampleRate: 4,
143
+ timestamp: 2
144
+ }
145
+ }
146
+
147
+ const mixed = await collect(mixer.mix(samples()))
148
+ expect(mixed.length).is(3)
149
+ expect(mixed[0].startFrame).is(0)
150
+ expect(mixed[0].planar[0]).is(1)
151
+
152
+ expect(mixed[1].startFrame).is(4)
153
+ expect(mixed[1].planar[0]).is(0)
154
+ expect(mixed[1].planar[3]).is(0)
155
+
156
+ expect(mixed[2].startFrame).is(8)
157
+ expect(mixed[2].planar[0]).is(2)
158
+ }),
159
+
160
+ "audio mix truncates negative timestamps": test(async () => {
161
+ const mixer = new AudioMix({chunkFrames: 4, clamp: false})
162
+ async function *samples() {
163
+ yield {
164
+ planes: [new Float32Array([1, 2, 3, 4])],
165
+ sampleRate: 4,
166
+ timestamp: -0.5
167
+ }
168
+ }
169
+
170
+ const mixed = await collect(mixer.mix(samples()))
171
+ expect(mixed.length).is(1)
172
+ expect(mixed[0].startFrame).is(0)
173
+ expect(mixed[0].planar[0]).is(3)
174
+ expect(mixed[0].planar[1]).is(4)
175
+ expect(mixed[0].planar[2]).is(0)
176
+ expect(mixed[0].planar[3]).is(0)
177
+ }),
178
+
179
+ "audio mix handles stereo planar layout": test(async () => {
180
+ const mixer = new AudioMix({chunkFrames: 4, clamp: false})
181
+ async function *samples() {
182
+ yield {
183
+ planes: [
184
+ new Float32Array([1, 1, 1, 1]),
185
+ new Float32Array([2, 2, 2, 2])
186
+ ],
187
+ sampleRate: 4,
188
+ timestamp: 0
189
+ }
190
+ }
191
+
192
+ const mixed = await collect(mixer.mix(samples()))
193
+ expect(mixed.length).is(1)
194
+ expect(mixed[0].channels).is(2)
195
+ expect(mixed[0].planar.length).is(8)
196
+ expect(mixed[0].planar[0]).is(1)
197
+ expect(mixed[0].planar[4]).is(2)
198
+ }),
199
+
200
+ "applyGainToPlanar scales values across multiple channels": test(async () => {
201
+ const planes = [
202
+ new Float32Array([0.2, -0.4]),
203
+ new Float32Array([0.6, -0.8])
204
+ ]
205
+
206
+ applyGainToPlanar(planes, 0.5)
207
+
208
+ expect(near(planes[0][0], 0.1)).ok()
209
+ expect(near(planes[0][1], -0.2)).ok()
210
+ expect(near(planes[1][0], 0.3)).ok()
211
+ expect(near(planes[1][1], -0.4)).ok()
212
+ }),
213
+
214
+ "applyGainToPlanar does not mutate when gain is 1": test(async () => {
215
+ const planes = [new Float32Array([0.5, -0.5])]
216
+
217
+ applyGainToPlanar(planes, 1)
218
+
219
+ expect(near(planes[0][0], 0.5)).ok()
220
+ expect(near(planes[0][1], -0.5)).ok()
221
+ }),
222
+
223
+ "applyGainToPlanar mutes entirely when gain is 0": test(async () => {
224
+ const planes = [new Float32Array([0.9, -0.9])]
225
+
226
+ applyGainToPlanar(planes, 0)
227
+
228
+ expect(planes[0][0]).is(0)
229
+ expect(planes[0][1]).is(0)
230
+ }),
231
+
232
+ "resampleToPlanar returns original data when sample rates match": test(async () => {
233
+ const sample = {
234
+ numberOfFrames: 3,
235
+ numberOfChannels: 1,
236
+ sampleRate: 48000,
237
+ copyTo: (dest: Float32Array) => dest.set([0.1, 0.2, 0.3])
238
+ }
239
+
240
+ const result = resampleToPlanar(sample, 48000)
241
+
242
+ expect(result.frames).is(3)
243
+ expect(result.data.length).is(1)
244
+ expect(near(result.data[0][0], 0.1)).ok()
245
+ expect(near(result.data[0][1], 0.2)).ok()
246
+ expect(near(result.data[0][2], 0.3)).ok()
247
+ }),
248
+
249
+ "resampleToPlanar upsamples using linear interpolation": test(async () => {
250
+ const sample = {
251
+ numberOfFrames: 2,
252
+ numberOfChannels: 1,
253
+ sampleRate: 1,
254
+ copyTo: (dest: Float32Array) => dest.set([10, 20])
255
+ }
256
+
257
+ const result = resampleToPlanar(sample as any, 2)
258
+
259
+ expect(result.frames).is(4)
260
+ expect(near(result.data[0][0], 10)).ok()
261
+ expect(near(result.data[0][1], 15)).ok()
262
+ expect(near(result.data[0][2], 20)).ok()
263
+ expect(near(result.data[0][3], 20)).ok()
264
+ }),
265
+
266
+ "resampleToPlanar downsamples correctly": test(async () => {
267
+ const sample = {
268
+ numberOfFrames: 4,
269
+ numberOfChannels: 1,
270
+ sampleRate: 4,
271
+ copyTo: (dest: Float32Array) => dest.set([1, 2, 3, 4])
272
+ }
273
+
274
+ const result = resampleToPlanar(sample, 2)
275
+
276
+ expect(result.frames).is(2)
277
+ expect(near(result.data[0][0], 1)).ok()
278
+ expect(near(result.data[0][1], 3)).ok()
279
+ }),
280
+
281
+ "resampleToPlanar processes multi-channel planar data": test(async () => {
282
+ const planes = [
283
+ new Float32Array([1, 2]),
284
+ new Float32Array([3, 4])
285
+ ]
286
+
287
+ const sample = {
288
+ numberOfFrames: 2,
289
+ numberOfChannels: 2,
290
+ sampleRate: 1,
291
+ copyTo: (dest: Float32Array, options: { planeIndex: number }) => {
292
+ dest.set(planes[options.planeIndex])
293
+ }
294
+ }
295
+
296
+ const result = resampleToPlanar(sample, 2)
297
+
298
+ expect(result.data.length).is(2)
299
+ expect(near(result.data[0][1], 1.5)).ok()
300
+ expect(near(result.data[1][1], 3.5)).ok()
301
+ }),
302
+
303
+ "resampleToPlanar handles zero channels gracefully": test(async () => {
304
+ const sample = {
305
+ numberOfFrames: 10,
306
+ numberOfChannels: 0,
307
+ sampleRate: 48000,
308
+ copyTo: () => { throw new Error("Should not be called") }
309
+ }
310
+
311
+ const result = resampleToPlanar(sample, 44100)
312
+
313
+ expect(result.data.length).is(0)
314
+ expect(result.frames).is(0)
315
+ }),
316
+
317
+ "resampleToPlanar enforces minimum of 1 frame on aggressive downsample": test(async () => {
318
+ const sample = {
319
+ numberOfFrames: 1,
320
+ numberOfChannels: 1,
321
+ sampleRate: 48000,
322
+ copyTo: (dest: Float32Array) => dest.set([0.8])
323
+ }
324
+
325
+ const result = resampleToPlanar(sample, 8000)
326
+
327
+ expect(result.frames).is(1)
328
+ expect(result.data[0].length).is(1)
329
+ expect(near(result.data[0][0], 0.8)).ok()
330
+ }),
331
+
332
+ "resampleToPlanar calls copyTo with strict contract shape": test(async () => {
333
+ let passedOptions: any = null
334
+ const sample = {
335
+ numberOfFrames: 2,
336
+ numberOfChannels: 1,
337
+ sampleRate: 48000,
338
+ copyTo: (dest: Float32Array, options: any) => {
339
+ passedOptions = options
340
+ }
341
+ }
342
+
343
+ resampleToPlanar(sample, 44100)
344
+
345
+ expect(passedOptions).not.is(null)
346
+ expect(passedOptions.planeIndex).is(0)
347
+ expect(passedOptions.format).is("f32-planar")
348
+ }),
349
+
350
+ "5s long export at 30fps renders exacly 150 frames": test(async () => {
351
+ const {omni, videoA, driver, resolveMedia} = await setupTest()
352
+ const {timeline} = new O({timeline: omni.timeline(o => o.sequence(
353
+ o.video(videoA, {duration: 2000}),
354
+ o.gap(500),
355
+ o.video(videoA, {duration: 2000}),
356
+ o.audio(videoA, {duration: 500})
357
+ ))})
358
+ const readable = produceVideo({timeline, fps: fps(30), driver, resolveMedia})
359
+ let frames = 0
360
+ for await (const frame of readable) {
361
+ frame.close()
362
+ frames++
363
+ }
364
+ expect(frames).is(150)
365
+ }),
366
+
367
+ "5s long audio export at 48000Hz renders exactly 240000 frames": test(async () => {
368
+ const {omni, videoA, resolveMedia} = await setupTest()
369
+ const {timeline} = new O({timeline: omni.timeline(o => o.sequence(
370
+ o.video(videoA, {duration: 2000}),
371
+ o.gap(500),
372
+ o.video(videoA, {duration: 2000}),
373
+ o.audio(videoA, {duration: 500})
374
+ ))})
375
+
376
+ const readable = produceAudio({timeline, resolveMedia})
377
+ let totalFrames = 0
378
+
379
+ for await (const chunk of readable) {
380
+ totalFrames += chunk.numberOfFrames
381
+ chunk.close()
382
+ }
383
+
384
+ expect(totalFrames).is(240000)
385
+ })
386
+ })
387
+
@@ -0,0 +1,85 @@
1
+
2
+ import {TextStyleOptions} from "pixi.js"
3
+
4
+ import {O} from "./o.js"
5
+ import {Item} from "../parts/item.js"
6
+ import {Transform} from "../types.js"
7
+ import {Media} from "../parts/media.js"
8
+ import {TimelineFile} from "../parts/basics.js"
9
+
10
+ type Build<T extends Item.Any = Item.Any> = (o: O) => T
11
+
12
+ function createTimeline(): TimelineFile {
13
+ return {
14
+ format: "timeline",
15
+ info: "https://omniclip.app/",
16
+ version: 0,
17
+ items: [],
18
+ rootId: 0
19
+ }
20
+ }
21
+
22
+ export function timeline(root: Build): TimelineFile {
23
+ const o = new O({timeline: createTimeline()})
24
+ const item = root(o)
25
+ o.timeline.rootId = item.id
26
+ return o.timeline
27
+ }
28
+
29
+ export function sequence(...items: Build[]): Build<Item.Sequence> {
30
+ return o => o.sequence(...items.map(item => item(o)))
31
+ }
32
+
33
+ export function stack(...items: Build[]): Build<Item.Stack> {
34
+ return o => o.stack(...items.map(item => item(o)))
35
+ }
36
+
37
+ export function video(
38
+ media: Media,
39
+ options?: {
40
+ start?: number,
41
+ duration?: number
42
+ }
43
+ ): Build<Item.Video> {
44
+ return o => o.video(media, options)
45
+ }
46
+
47
+ export function audio(
48
+ media: Media,
49
+ options?: {
50
+ start?: number,
51
+ duration?: number,
52
+ gain?: number
53
+ }
54
+ ): Build<Item.Audio> {
55
+ return o => o.audio(media, options)
56
+ }
57
+
58
+ export function text(
59
+ content: string,
60
+ options?: {
61
+ duration?: number,
62
+ styles?: TextStyleOptions
63
+ }
64
+ ): Build<Item.Text> {
65
+ return o => o.text(content, options)
66
+ }
67
+
68
+ export function gap(duration: number): Build<Item.Gap> {
69
+ return o => o.gap(duration)
70
+ }
71
+
72
+ export function spatial(transform: Transform): Build<Item.Spatial> {
73
+ return o => o.spatial(transform)
74
+ }
75
+
76
+ export function textStyle(style: TextStyleOptions): Build<Item.TextStyle> {
77
+ return o => o.textStyle(style)
78
+ }
79
+
80
+ export const transition = {
81
+ crossfade(duration: number): Build<Item.Transition> {
82
+ return o => o.transition.crossfade(duration)
83
+ }
84
+ }
85
+
@@ -1,60 +1,200 @@
1
+ import {hex} from "@e280/stz"
2
+ import {TextStyleOptions} from "pixi.js"
1
3
 
2
- import {MapG} from "@e280/stz"
3
- import {Id} from "../parts/basics.js"
4
4
  import {Media} from "../parts/media.js"
5
+ import {Id, TimelineFile} from "../parts/basics.js"
5
6
  import {Effect, Item, Kind} from "../parts/item.js"
7
+ import {Transform, TransformOptions, Vec2} from "../types.js"
6
8
 
7
9
  export class O {
8
- #nextId = 0
9
- #items = new MapG<Id, Item.Any>()
10
+ constructor(public state: {timeline: TimelineFile}) {}
11
+
12
+ require<T extends Item.Any>(id: Id | undefined) {
13
+ if (id === undefined)
14
+ return undefined
15
+ const item = this.state.timeline.items.find(item => item.id === id)
16
+ return item as T | undefined
17
+ }
18
+
19
+ get timeline() {
20
+ return this.state.timeline
21
+ }
10
22
 
11
23
  #getId() {
12
- return this.#nextId++
24
+ return hex.toInteger(hex.random())
13
25
  }
14
26
 
27
+ #mutate(fn: (project: TimelineFile) => TimelineFile) {
28
+ this.state.timeline = fn(this.state.timeline)
29
+ }
30
+
15
31
  register(item: Item.Any) {
16
- if (!this.#items.has(item.id))
17
- this.#items.set(item.id, item)
18
- return item.id
32
+ this.#mutate(state => ({
33
+ ...state,
34
+ items: [...state.items, item]
35
+ }))
36
+ }
37
+
38
+ textStyle = (style: TextStyleOptions): Item.TextStyle => {
39
+ const item = {
40
+ id: this.#getId(),
41
+ kind: Kind.TextStyle,
42
+ style
43
+ } as Item.TextStyle
44
+ this.register(item)
45
+ return item
46
+ }
47
+
48
+ spatial = (transform: Transform): Item.Spatial => {
49
+ const item: Item.Spatial = {
50
+ id: this.#getId(),
51
+ kind: Kind.Spatial,
52
+ transform,
53
+ enabled: true
54
+ }
55
+ this.register(item)
56
+ return item
57
+ }
58
+
59
+ sequence = (...items: Item.Any[]): Item.Sequence => {
60
+ const item = {
61
+ id: this.#getId(),
62
+ kind: Kind.Sequence,
63
+ childrenIds: items.map(item => item.id)
64
+ } as Item.Sequence
65
+ this.register(item)
66
+ return item
19
67
  }
20
68
 
21
- get items() {
22
- return [...this.#items.values()]
69
+ stack = (...items: Item.Any[]): Item.Stack => {
70
+ const item = {
71
+ kind: Kind.Stack,
72
+ id: this.#getId(),
73
+ childrenIds: items.map(item => item.id)
74
+ } as Item.Stack
75
+ this.register(item)
76
+ return item
23
77
  }
24
78
 
25
- sequence = (...items: Item.Any[]): Item.Sequence => ({
26
- id: this.#getId(),
27
- kind: Kind.Sequence,
28
- children: items.map(item => this.register(item)),
29
- })
79
+ video = (
80
+ media: Media,
81
+ options?: {
82
+ start?: number,
83
+ duration?: number
84
+ }): Item.Video => {
30
85
 
31
- stack = (...items: Item.Any[]): Item.Stack => ({
32
- id: this.#getId(),
33
- kind: Kind.Stack,
34
- children: items.map(item => this.register(item)),
35
- })
86
+ if(!media.hasVideo)
87
+ throw new Error(`Video clip error: media "${media.datafile.filename}" has no video track.`)
36
88
 
37
- clip = (media: Media, start?: number, duration?: number): Item.Clip => ({
38
- id: this.#getId(),
39
- kind: Kind.Clip,
40
- mediaHash: media.datafile.checksum.hash,
41
- start: start ?? 0,
42
- duration: duration ?? media.duration,
43
- })
89
+ const item: Item.Video = {
90
+ kind: Kind.Video,
91
+ id: this.#getId(),
92
+ mediaHash: media.datafile.checksum.hash,
93
+ start: options?.start ?? 0,
94
+ duration: options?.duration ?? media.duration
95
+ }
96
+ this.register(item)
97
+ return item
98
+ }
44
99
 
45
- text = (content: string): Item.Text => ({
46
- id: this.#getId(),
47
- kind: Kind.Text,
48
- content,
49
- })
100
+ audio = (
101
+ media: Media,
102
+ options?: {
103
+ start?: number,
104
+ duration?: number,
105
+ gain?: number
106
+ }): Item.Audio => {
50
107
 
51
- transition = {
52
- crossfade: (duration: number): Item.Transition => ({
108
+ if(!media.hasAudio)
109
+ throw new Error(`Audio clip error: media "${media.datafile.filename}" has no audio track.`)
110
+
111
+ const item: Item.Audio = {
112
+ kind: Kind.Audio,
53
113
  id: this.#getId(),
54
- kind: Kind.Transition,
55
- effect: Effect.Crossfade,
56
- duration,
57
- }),
114
+ mediaHash: media.datafile.checksum.hash,
115
+ start: options?.start ?? 0,
116
+ duration: options?.duration ?? media.duration,
117
+ gain: options?.gain ?? 1
118
+ }
119
+ this.register(item)
120
+ return item
121
+ }
122
+
123
+ text = (content: string, options?: {
124
+ duration?: number,
125
+ styles?: TextStyleOptions
126
+ }): Item.Text => {
127
+
128
+ const item = {
129
+ id: this.#getId(),
130
+ content,
131
+ kind: Kind.Text,
132
+ duration: options?.duration ?? 2000
133
+ } as Item.Text
134
+
135
+ if(options?.styles)
136
+ item.styleId = this.textStyle(options.styles).id
137
+
138
+ this.register(item)
139
+ return item
140
+ }
141
+
142
+ gap = (duration: number): Item.Gap => {
143
+ const item = {
144
+ id: this.#getId(),
145
+ kind: Kind.Gap,
146
+ duration
147
+ } as Item.Gap
148
+ this.register(item)
149
+ return item
150
+ }
151
+
152
+ transition = {
153
+ crossfade: (duration: number): Item.Transition => {
154
+ const item = {
155
+ id: this.#getId(),
156
+ kind: Kind.Transition,
157
+ effect: Effect.Crossfade,
158
+ duration,
159
+ } as Item.Transition
160
+ this.register(item)
161
+ return item
162
+ },
163
+ }
164
+
165
+ transform = (options?: TransformOptions): Transform => {
166
+ const position: Vec2 = [
167
+ options?.position?.[0] ?? 0,
168
+ options?.position?.[1] ?? 0
169
+ ]
170
+ const scale: Vec2 = [
171
+ options?.scale?.[0] ?? 1,
172
+ options?.scale?.[1] ?? 1
173
+ ]
174
+ const rotation = options?.rotation ?? 0
175
+ return [position, scale, rotation]
176
+ }
177
+
178
+ addChildren(parent: Item.Stack | Item.Sequence, ...items: Item.Any[]) {
179
+ this.#mutate(state => {
180
+ const parentItem = state.items.find(({id}) => id === parent.id) as Item.Stack
181
+ parentItem.childrenIds.push(...items.map(item => item.id))
182
+ return state
183
+ })
184
+ }
185
+
186
+ set = <K extends Item.Any>(
187
+ id: Id,
188
+ partial: Partial<K>
189
+ ) => {
190
+ this.#mutate(project => ({
191
+ ...project,
192
+ items: project.items.map(item =>
193
+ item.id === id
194
+ ? { ...item, ...partial }
195
+ : item
196
+ )
197
+ }))
58
198
  }
59
199
  }
60
200