@nodetool-ai/base-nodes 0.7.0-rc.11

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 (353) hide show
  1. package/dist/index.d.ts +72 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +270 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/lib/audio-wav.d.ts +66 -0
  6. package/dist/lib/audio-wav.d.ts.map +1 -0
  7. package/dist/lib/audio-wav.js +215 -0
  8. package/dist/lib/audio-wav.js.map +1 -0
  9. package/dist/nodes/agents.d.ts +253 -0
  10. package/dist/nodes/agents.d.ts.map +1 -0
  11. package/dist/nodes/agents.js +2784 -0
  12. package/dist/nodes/agents.js.map +1 -0
  13. package/dist/nodes/anthropic.d.ts +26 -0
  14. package/dist/nodes/anthropic.d.ts.map +1 -0
  15. package/dist/nodes/anthropic.js +133 -0
  16. package/dist/nodes/anthropic.js.map +1 -0
  17. package/dist/nodes/apify.d.ts +120 -0
  18. package/dist/nodes/apify.d.ts.map +1 -0
  19. package/dist/nodes/apify.js +618 -0
  20. package/dist/nodes/apify.js.map +1 -0
  21. package/dist/nodes/audio.d.ts +301 -0
  22. package/dist/nodes/audio.d.ts.map +1 -0
  23. package/dist/nodes/audio.js +1274 -0
  24. package/dist/nodes/audio.js.map +1 -0
  25. package/dist/nodes/code-node.d.ts +34 -0
  26. package/dist/nodes/code-node.d.ts.map +1 -0
  27. package/dist/nodes/code-node.js +343 -0
  28. package/dist/nodes/code-node.js.map +1 -0
  29. package/dist/nodes/code.d.ts +301 -0
  30. package/dist/nodes/code.d.ts.map +1 -0
  31. package/dist/nodes/code.js +850 -0
  32. package/dist/nodes/code.js.map +1 -0
  33. package/dist/nodes/compare.d.ts +18 -0
  34. package/dist/nodes/compare.d.ts.map +1 -0
  35. package/dist/nodes/compare.js +122 -0
  36. package/dist/nodes/compare.js.map +1 -0
  37. package/dist/nodes/constant.d.ts +315 -0
  38. package/dist/nodes/constant.d.ts.map +1 -0
  39. package/dist/nodes/constant.js +715 -0
  40. package/dist/nodes/constant.js.map +1 -0
  41. package/dist/nodes/control.d.ts +83 -0
  42. package/dist/nodes/control.d.ts.map +1 -0
  43. package/dist/nodes/control.js +212 -0
  44. package/dist/nodes/control.js.map +1 -0
  45. package/dist/nodes/data.d.ts +369 -0
  46. package/dist/nodes/data.d.ts.map +1 -0
  47. package/dist/nodes/data.js +1590 -0
  48. package/dist/nodes/data.js.map +1 -0
  49. package/dist/nodes/document.d.ts +134 -0
  50. package/dist/nodes/document.d.ts.map +1 -0
  51. package/dist/nodes/document.js +984 -0
  52. package/dist/nodes/document.js.map +1 -0
  53. package/dist/nodes/extended-placeholders.d.ts +6 -0
  54. package/dist/nodes/extended-placeholders.d.ts.map +1 -0
  55. package/dist/nodes/extended-placeholders.js +19 -0
  56. package/dist/nodes/extended-placeholders.js.map +1 -0
  57. package/dist/nodes/gemini.d.ts +109 -0
  58. package/dist/nodes/gemini.d.ts.map +1 -0
  59. package/dist/nodes/gemini.js +861 -0
  60. package/dist/nodes/gemini.js.map +1 -0
  61. package/dist/nodes/generators.d.ts +84 -0
  62. package/dist/nodes/generators.d.ts.map +1 -0
  63. package/dist/nodes/generators.js +937 -0
  64. package/dist/nodes/generators.js.map +1 -0
  65. package/dist/nodes/image.d.ts +232 -0
  66. package/dist/nodes/image.d.ts.map +1 -0
  67. package/dist/nodes/image.js +1395 -0
  68. package/dist/nodes/image.js.map +1 -0
  69. package/dist/nodes/input.d.ts +445 -0
  70. package/dist/nodes/input.d.ts.map +1 -0
  71. package/dist/nodes/input.js +1459 -0
  72. package/dist/nodes/input.js.map +1 -0
  73. package/dist/nodes/kie-dynamic.d.ts +31 -0
  74. package/dist/nodes/kie-dynamic.d.ts.map +1 -0
  75. package/dist/nodes/kie-dynamic.js +270 -0
  76. package/dist/nodes/kie-dynamic.js.map +1 -0
  77. package/dist/nodes/lib-audio-dsp.d.ts +85 -0
  78. package/dist/nodes/lib-audio-dsp.d.ts.map +1 -0
  79. package/dist/nodes/lib-audio-dsp.js +450 -0
  80. package/dist/nodes/lib-audio-dsp.js.map +1 -0
  81. package/dist/nodes/lib-audio-effects.d.ts +116 -0
  82. package/dist/nodes/lib-audio-effects.d.ts.map +1 -0
  83. package/dist/nodes/lib-audio-effects.js +905 -0
  84. package/dist/nodes/lib-audio-effects.js.map +1 -0
  85. package/dist/nodes/lib-browser.d.ts +99 -0
  86. package/dist/nodes/lib-browser.d.ts.map +1 -0
  87. package/dist/nodes/lib-browser.js +692 -0
  88. package/dist/nodes/lib-browser.js.map +1 -0
  89. package/dist/nodes/lib-charts.d.ts +20 -0
  90. package/dist/nodes/lib-charts.d.ts.map +1 -0
  91. package/dist/nodes/lib-charts.js +245 -0
  92. package/dist/nodes/lib-charts.js.map +1 -0
  93. package/dist/nodes/lib-datetime.d.ts +108 -0
  94. package/dist/nodes/lib-datetime.d.ts.map +1 -0
  95. package/dist/nodes/lib-datetime.js +421 -0
  96. package/dist/nodes/lib-datetime.js.map +1 -0
  97. package/dist/nodes/lib-doc-convert.d.ts +19 -0
  98. package/dist/nodes/lib-doc-convert.d.ts.map +1 -0
  99. package/dist/nodes/lib-doc-convert.js +257 -0
  100. package/dist/nodes/lib-doc-convert.js.map +1 -0
  101. package/dist/nodes/lib-doc-transform.d.ts +39 -0
  102. package/dist/nodes/lib-doc-transform.d.ts.map +1 -0
  103. package/dist/nodes/lib-doc-transform.js +335 -0
  104. package/dist/nodes/lib-doc-transform.js.map +1 -0
  105. package/dist/nodes/lib-docx.d.ts +106 -0
  106. package/dist/nodes/lib-docx.d.ts.map +1 -0
  107. package/dist/nodes/lib-docx.js +595 -0
  108. package/dist/nodes/lib-docx.js.map +1 -0
  109. package/dist/nodes/lib-epub.d.ts +55 -0
  110. package/dist/nodes/lib-epub.d.ts.map +1 -0
  111. package/dist/nodes/lib-epub.js +220 -0
  112. package/dist/nodes/lib-epub.js.map +1 -0
  113. package/dist/nodes/lib-excel.d.ts +74 -0
  114. package/dist/nodes/lib-excel.d.ts.map +1 -0
  115. package/dist/nodes/lib-excel.js +448 -0
  116. package/dist/nodes/lib-excel.js.map +1 -0
  117. package/dist/nodes/lib-graphql.d.ts +66 -0
  118. package/dist/nodes/lib-graphql.d.ts.map +1 -0
  119. package/dist/nodes/lib-graphql.js +333 -0
  120. package/dist/nodes/lib-graphql.js.map +1 -0
  121. package/dist/nodes/lib-grid.d.ts +27 -0
  122. package/dist/nodes/lib-grid.d.ts.map +1 -0
  123. package/dist/nodes/lib-grid.js +172 -0
  124. package/dist/nodes/lib-grid.js.map +1 -0
  125. package/dist/nodes/lib-html-parse.d.ts +108 -0
  126. package/dist/nodes/lib-html-parse.d.ts.map +1 -0
  127. package/dist/nodes/lib-html-parse.js +365 -0
  128. package/dist/nodes/lib-html-parse.js.map +1 -0
  129. package/dist/nodes/lib-http.d.ts +98 -0
  130. package/dist/nodes/lib-http.d.ts.map +1 -0
  131. package/dist/nodes/lib-http.js +267 -0
  132. package/dist/nodes/lib-http.js.map +1 -0
  133. package/dist/nodes/lib-image-color-grading.d.ts +3 -0
  134. package/dist/nodes/lib-image-color-grading.d.ts.map +1 -0
  135. package/dist/nodes/lib-image-color-grading.js +1386 -0
  136. package/dist/nodes/lib-image-color-grading.js.map +1 -0
  137. package/dist/nodes/lib-image-draw.d.ts +3 -0
  138. package/dist/nodes/lib-image-draw.d.ts.map +1 -0
  139. package/dist/nodes/lib-image-draw.js +470 -0
  140. package/dist/nodes/lib-image-draw.js.map +1 -0
  141. package/dist/nodes/lib-image-enhance.d.ts +3 -0
  142. package/dist/nodes/lib-image-enhance.d.ts.map +1 -0
  143. package/dist/nodes/lib-image-enhance.js +731 -0
  144. package/dist/nodes/lib-image-enhance.js.map +1 -0
  145. package/dist/nodes/lib-image-filter.d.ts +3 -0
  146. package/dist/nodes/lib-image-filter.d.ts.map +1 -0
  147. package/dist/nodes/lib-image-filter.js +684 -0
  148. package/dist/nodes/lib-image-filter.js.map +1 -0
  149. package/dist/nodes/lib-image-utils.d.ts +24 -0
  150. package/dist/nodes/lib-image-utils.d.ts.map +1 -0
  151. package/dist/nodes/lib-image-utils.js +150 -0
  152. package/dist/nodes/lib-image-utils.js.map +1 -0
  153. package/dist/nodes/lib-mail.d.ts +74 -0
  154. package/dist/nodes/lib-mail.d.ts.map +1 -0
  155. package/dist/nodes/lib-mail.js +452 -0
  156. package/dist/nodes/lib-mail.js.map +1 -0
  157. package/dist/nodes/lib-markdown.d.ts +70 -0
  158. package/dist/nodes/lib-markdown.d.ts.map +1 -0
  159. package/dist/nodes/lib-markdown.js +236 -0
  160. package/dist/nodes/lib-markdown.js.map +1 -0
  161. package/dist/nodes/lib-nlp.d.ts +98 -0
  162. package/dist/nodes/lib-nlp.d.ts.map +1 -0
  163. package/dist/nodes/lib-nlp.js +374 -0
  164. package/dist/nodes/lib-nlp.js.map +1 -0
  165. package/dist/nodes/lib-notion.d.ts +99 -0
  166. package/dist/nodes/lib-notion.d.ts.map +1 -0
  167. package/dist/nodes/lib-notion.js +601 -0
  168. package/dist/nodes/lib-notion.js.map +1 -0
  169. package/dist/nodes/lib-ocr.d.ts +31 -0
  170. package/dist/nodes/lib-ocr.d.ts.map +1 -0
  171. package/dist/nodes/lib-ocr.js +143 -0
  172. package/dist/nodes/lib-ocr.js.map +1 -0
  173. package/dist/nodes/lib-os.d.ts +312 -0
  174. package/dist/nodes/lib-os.d.ts.map +1 -0
  175. package/dist/nodes/lib-os.js +909 -0
  176. package/dist/nodes/lib-os.js.map +1 -0
  177. package/dist/nodes/lib-pdf.d.ts +142 -0
  178. package/dist/nodes/lib-pdf.d.ts.map +1 -0
  179. package/dist/nodes/lib-pdf.js +871 -0
  180. package/dist/nodes/lib-pdf.js.map +1 -0
  181. package/dist/nodes/lib-pptx.d.ts +29 -0
  182. package/dist/nodes/lib-pptx.d.ts.map +1 -0
  183. package/dist/nodes/lib-pptx.js +122 -0
  184. package/dist/nodes/lib-pptx.js.map +1 -0
  185. package/dist/nodes/lib-rss.d.ts +31 -0
  186. package/dist/nodes/lib-rss.d.ts.map +1 -0
  187. package/dist/nodes/lib-rss.js +163 -0
  188. package/dist/nodes/lib-rss.js.map +1 -0
  189. package/dist/nodes/lib-s3.d.ts +112 -0
  190. package/dist/nodes/lib-s3.d.ts.map +1 -0
  191. package/dist/nodes/lib-s3.js +521 -0
  192. package/dist/nodes/lib-s3.js.map +1 -0
  193. package/dist/nodes/lib-secret.d.ts +15 -0
  194. package/dist/nodes/lib-secret.d.ts.map +1 -0
  195. package/dist/nodes/lib-secret.js +42 -0
  196. package/dist/nodes/lib-secret.js.map +1 -0
  197. package/dist/nodes/lib-sqlite.d.ts +102 -0
  198. package/dist/nodes/lib-sqlite.d.ts.map +1 -0
  199. package/dist/nodes/lib-sqlite.js +532 -0
  200. package/dist/nodes/lib-sqlite.js.map +1 -0
  201. package/dist/nodes/lib-supabase.d.ts +86 -0
  202. package/dist/nodes/lib-supabase.d.ts.map +1 -0
  203. package/dist/nodes/lib-supabase.js +425 -0
  204. package/dist/nodes/lib-supabase.js.map +1 -0
  205. package/dist/nodes/lib-svg.d.ts +199 -0
  206. package/dist/nodes/lib-svg.d.ts.map +1 -0
  207. package/dist/nodes/lib-svg.js +1027 -0
  208. package/dist/nodes/lib-svg.js.map +1 -0
  209. package/dist/nodes/lib-tensorflow.d.ts +71 -0
  210. package/dist/nodes/lib-tensorflow.d.ts.map +1 -0
  211. package/dist/nodes/lib-tensorflow.js +351 -0
  212. package/dist/nodes/lib-tensorflow.js.map +1 -0
  213. package/dist/nodes/lib-twilio.d.ts +71 -0
  214. package/dist/nodes/lib-twilio.d.ts.map +1 -0
  215. package/dist/nodes/lib-twilio.js +469 -0
  216. package/dist/nodes/lib-twilio.js.map +1 -0
  217. package/dist/nodes/lib-validate.d.ts +84 -0
  218. package/dist/nodes/lib-validate.d.ts.map +1 -0
  219. package/dist/nodes/lib-validate.js +215 -0
  220. package/dist/nodes/lib-validate.js.map +1 -0
  221. package/dist/nodes/lib-video-download.d.ts +26 -0
  222. package/dist/nodes/lib-video-download.d.ts.map +1 -0
  223. package/dist/nodes/lib-video-download.js +299 -0
  224. package/dist/nodes/lib-video-download.js.map +1 -0
  225. package/dist/nodes/messaging.d.ts +88 -0
  226. package/dist/nodes/messaging.d.ts.map +1 -0
  227. package/dist/nodes/messaging.js +418 -0
  228. package/dist/nodes/messaging.js.map +1 -0
  229. package/dist/nodes/mistral.d.ts +83 -0
  230. package/dist/nodes/mistral.d.ts.map +1 -0
  231. package/dist/nodes/mistral.js +450 -0
  232. package/dist/nodes/mistral.js.map +1 -0
  233. package/dist/nodes/model3d/analysis.d.ts +13 -0
  234. package/dist/nodes/model3d/analysis.d.ts.map +1 -0
  235. package/dist/nodes/model3d/analysis.js +36 -0
  236. package/dist/nodes/model3d/analysis.js.map +1 -0
  237. package/dist/nodes/model3d/base.d.ts +11 -0
  238. package/dist/nodes/model3d/base.d.ts.map +1 -0
  239. package/dist/nodes/model3d/base.js +20 -0
  240. package/dist/nodes/model3d/base.js.map +1 -0
  241. package/dist/nodes/model3d/boolean-ops.d.ts +2 -0
  242. package/dist/nodes/model3d/boolean-ops.d.ts.map +1 -0
  243. package/dist/nodes/model3d/boolean-ops.js +172 -0
  244. package/dist/nodes/model3d/boolean-ops.js.map +1 -0
  245. package/dist/nodes/model3d/cleanup.d.ts +47 -0
  246. package/dist/nodes/model3d/cleanup.d.ts.map +1 -0
  247. package/dist/nodes/model3d/cleanup.js +136 -0
  248. package/dist/nodes/model3d/cleanup.js.map +1 -0
  249. package/dist/nodes/model3d/convert.d.ts +14 -0
  250. package/dist/nodes/model3d/convert.d.ts.map +1 -0
  251. package/dist/nodes/model3d/convert.js +64 -0
  252. package/dist/nodes/model3d/convert.js.map +1 -0
  253. package/dist/nodes/model3d/defaults.d.ts +34 -0
  254. package/dist/nodes/model3d/defaults.d.ts.map +1 -0
  255. package/dist/nodes/model3d/defaults.js +28 -0
  256. package/dist/nodes/model3d/defaults.js.map +1 -0
  257. package/dist/nodes/model3d/document-ops.d.ts +4 -0
  258. package/dist/nodes/model3d/document-ops.d.ts.map +1 -0
  259. package/dist/nodes/model3d/document-ops.js +40 -0
  260. package/dist/nodes/model3d/document-ops.js.map +1 -0
  261. package/dist/nodes/model3d/generation.d.ts +39 -0
  262. package/dist/nodes/model3d/generation.d.ts.map +1 -0
  263. package/dist/nodes/model3d/generation.js +179 -0
  264. package/dist/nodes/model3d/generation.js.map +1 -0
  265. package/dist/nodes/model3d/glb.d.ts +29 -0
  266. package/dist/nodes/model3d/glb.d.ts.map +1 -0
  267. package/dist/nodes/model3d/glb.js +255 -0
  268. package/dist/nodes/model3d/glb.js.map +1 -0
  269. package/dist/nodes/model3d/index.d.ts +20 -0
  270. package/dist/nodes/model3d/index.d.ts.map +1 -0
  271. package/dist/nodes/model3d/index.js +38 -0
  272. package/dist/nodes/model3d/index.js.map +1 -0
  273. package/dist/nodes/model3d/io.d.ts +38 -0
  274. package/dist/nodes/model3d/io.d.ts.map +1 -0
  275. package/dist/nodes/model3d/io.js +162 -0
  276. package/dist/nodes/model3d/io.js.map +1 -0
  277. package/dist/nodes/model3d/mesh-ops.d.ts +40 -0
  278. package/dist/nodes/model3d/mesh-ops.d.ts.map +1 -0
  279. package/dist/nodes/model3d/mesh-ops.js +775 -0
  280. package/dist/nodes/model3d/mesh-ops.js.map +1 -0
  281. package/dist/nodes/model3d/nodes.d.ts +2 -0
  282. package/dist/nodes/model3d/nodes.d.ts.map +1 -0
  283. package/dist/nodes/model3d/nodes.js +2 -0
  284. package/dist/nodes/model3d/nodes.js.map +1 -0
  285. package/dist/nodes/model3d/ops.d.ts +37 -0
  286. package/dist/nodes/model3d/ops.d.ts.map +1 -0
  287. package/dist/nodes/model3d/ops.js +137 -0
  288. package/dist/nodes/model3d/ops.js.map +1 -0
  289. package/dist/nodes/model3d/transforms.d.ts +49 -0
  290. package/dist/nodes/model3d/transforms.d.ts.map +1 -0
  291. package/dist/nodes/model3d/transforms.js +142 -0
  292. package/dist/nodes/model3d/transforms.js.map +1 -0
  293. package/dist/nodes/model3d/types.d.ts +81 -0
  294. package/dist/nodes/model3d/types.d.ts.map +1 -0
  295. package/dist/nodes/model3d/types.js +2 -0
  296. package/dist/nodes/model3d/types.js.map +1 -0
  297. package/dist/nodes/model3d/utils.d.ts +34 -0
  298. package/dist/nodes/model3d/utils.d.ts.map +1 -0
  299. package/dist/nodes/model3d/utils.js +185 -0
  300. package/dist/nodes/model3d/utils.js.map +1 -0
  301. package/dist/nodes/model3d.d.ts +2 -0
  302. package/dist/nodes/model3d.d.ts.map +1 -0
  303. package/dist/nodes/model3d.js +2 -0
  304. package/dist/nodes/model3d.js.map +1 -0
  305. package/dist/nodes/openai.d.ts +172 -0
  306. package/dist/nodes/openai.d.ts.map +1 -0
  307. package/dist/nodes/openai.js +1294 -0
  308. package/dist/nodes/openai.js.map +1 -0
  309. package/dist/nodes/output.d.ts +29 -0
  310. package/dist/nodes/output.d.ts.map +1 -0
  311. package/dist/nodes/output.js +87 -0
  312. package/dist/nodes/output.js.map +1 -0
  313. package/dist/nodes/sandbox.d.ts +67 -0
  314. package/dist/nodes/sandbox.d.ts.map +1 -0
  315. package/dist/nodes/sandbox.js +681 -0
  316. package/dist/nodes/sandbox.js.map +1 -0
  317. package/dist/nodes/search.d.ts +117 -0
  318. package/dist/nodes/search.d.ts.map +1 -0
  319. package/dist/nodes/search.js +607 -0
  320. package/dist/nodes/search.js.map +1 -0
  321. package/dist/nodes/team.d.ts +74 -0
  322. package/dist/nodes/team.d.ts.map +1 -0
  323. package/dist/nodes/team.js +304 -0
  324. package/dist/nodes/team.js.map +1 -0
  325. package/dist/nodes/text-extra.d.ts +633 -0
  326. package/dist/nodes/text-extra.d.ts.map +1 -0
  327. package/dist/nodes/text-extra.js +2226 -0
  328. package/dist/nodes/text-extra.js.map +1 -0
  329. package/dist/nodes/tool-agents.d.ts +334 -0
  330. package/dist/nodes/tool-agents.d.ts.map +1 -0
  331. package/dist/nodes/tool-agents.js +1861 -0
  332. package/dist/nodes/tool-agents.js.map +1 -0
  333. package/dist/nodes/triggers.d.ts +107 -0
  334. package/dist/nodes/triggers.d.ts.map +1 -0
  335. package/dist/nodes/triggers.js +706 -0
  336. package/dist/nodes/triggers.js.map +1 -0
  337. package/dist/nodes/vector.d.ts +168 -0
  338. package/dist/nodes/vector.d.ts.map +1 -0
  339. package/dist/nodes/vector.js +1121 -0
  340. package/dist/nodes/vector.js.map +1 -0
  341. package/dist/nodes/video.d.ts +387 -0
  342. package/dist/nodes/video.d.ts.map +1 -0
  343. package/dist/nodes/video.js +2361 -0
  344. package/dist/nodes/video.js.map +1 -0
  345. package/dist/nodes/workflow.d.ts +24 -0
  346. package/dist/nodes/workflow.d.ts.map +1 -0
  347. package/dist/nodes/workflow.js +146 -0
  348. package/dist/nodes/workflow.js.map +1 -0
  349. package/dist/nodes/workspace.d.ts +203 -0
  350. package/dist/nodes/workspace.d.ts.map +1 -0
  351. package/dist/nodes/workspace.js +795 -0
  352. package/dist/nodes/workspace.js.map +1 -0
  353. package/package.json +103 -0
@@ -0,0 +1,905 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { BaseNode, prop } from "@nodetool-ai/node-sdk";
8
+ import { audioRefFromWav, decodeWav, encodeWav } from "../lib/audio-wav.js";
9
+ // ── DSP helpers ────────────────────────────────────────────────────
10
+ function processPerChannel(wav, fn) {
11
+ const { samples, sampleRate, numChannels } = wav;
12
+ const frameSamples = Math.floor(samples.length / numChannels);
13
+ const channels = [];
14
+ for (let ch = 0; ch < numChannels; ch++) {
15
+ const channelData = new Float32Array(frameSamples);
16
+ for (let i = 0; i < frameSamples; i++) {
17
+ channelData[i] = samples[i * numChannels + ch];
18
+ }
19
+ channels.push(fn(channelData, sampleRate));
20
+ }
21
+ const outFrames = channels[0].length;
22
+ const outSamples = new Float32Array(outFrames * numChannels);
23
+ for (let ch = 0; ch < numChannels; ch++) {
24
+ for (let i = 0; i < outFrames; i++) {
25
+ outSamples[i * numChannels + ch] = channels[ch][i];
26
+ }
27
+ }
28
+ return { samples: outSamples, sampleRate, numChannels };
29
+ }
30
+ // ── Bitcrush ──────────────────────────────────────────────────────
31
+ export class BitcrushNode extends BaseNode {
32
+ static nodeType = "lib.audio.Bitcrush";
33
+ static title = "Bitcrush";
34
+ static description = "Applies a bitcrushing effect to an audio file, reducing bit depth and/or sample rate.\n audio, effect, distortion\n\n Use cases:\n - Create lo-fi or retro-style audio effects\n - Simulate vintage digital audio equipment\n - Add digital distortion and artifacts to sounds";
35
+ static metadataOutputTypes = {
36
+ output: "audio"
37
+ };
38
+ async process() {
39
+ const audio = (this.audio ?? {});
40
+ const bitDepth = Number(this.bit_depth ?? 8);
41
+ const srrFactor = Number(this.sample_rate_reduction ?? 1);
42
+ if (!audio.data)
43
+ return { output: audio };
44
+ const wav = decodeWav(audio);
45
+ const result = processPerChannel(wav, (ch) => {
46
+ const levels = Math.pow(2, bitDepth - 1) - 1;
47
+ const out = new Float32Array(ch.length);
48
+ for (let i = 0; i < ch.length; i++) {
49
+ const idx = Math.floor(i / srrFactor) * srrFactor;
50
+ const srcIdx = Math.min(idx, ch.length - 1);
51
+ out[i] = Math.round(ch[srcIdx] * levels) / levels;
52
+ }
53
+ return out;
54
+ });
55
+ return {
56
+ output: audioRefFromWav(encodeWav(result.samples, result.sampleRate, result.numChannels))
57
+ };
58
+ }
59
+ }
60
+ __decorate([
61
+ prop({
62
+ type: "audio",
63
+ default: {
64
+ type: "audio",
65
+ uri: "",
66
+ asset_id: null,
67
+ data: null,
68
+ metadata: null
69
+ },
70
+ title: "Audio",
71
+ description: "The audio file to process."
72
+ })
73
+ ], BitcrushNode.prototype, "audio", void 0);
74
+ __decorate([
75
+ prop({
76
+ type: "int",
77
+ default: 8,
78
+ title: "Bit Depth",
79
+ description: "The bit depth to reduce the audio to. Lower values create more distortion.",
80
+ min: 1,
81
+ max: 16
82
+ })
83
+ ], BitcrushNode.prototype, "bit_depth", void 0);
84
+ __decorate([
85
+ prop({
86
+ type: "int",
87
+ default: 1,
88
+ title: "Sample Rate Reduction",
89
+ description: "Factor by which to reduce the sample rate. Higher values create more aliasing.",
90
+ min: 1,
91
+ max: 100
92
+ })
93
+ ], BitcrushNode.prototype, "sample_rate_reduction", void 0);
94
+ // ── Compress ──────────────────────────────────────────────────────
95
+ export class CompressNode extends BaseNode {
96
+ static nodeType = "lib.audio.Compress";
97
+ static title = "Compress";
98
+ static description = "Applies dynamic range compression to an audio file.\n audio, effect, dynamics\n\n Use cases:\n - Even out volume levels in a recording\n - Increase perceived loudness of audio\n - Control peaks in audio signals";
99
+ static metadataOutputTypes = {
100
+ output: "audio"
101
+ };
102
+ async process() {
103
+ const audio = (this.audio ?? {});
104
+ const thresholdDb = Number(this.threshold ?? -20);
105
+ const ratio = Number(this.ratio ?? 4);
106
+ const attackMs = Number(this.attack ?? 5);
107
+ const releaseMs = Number(this.release ?? 50);
108
+ if (!audio.data)
109
+ return { output: audio };
110
+ const wav = decodeWav(audio);
111
+ const result = processPerChannel(wav, (ch, sr) => {
112
+ const out = new Float32Array(ch.length);
113
+ const attackCoeff = Math.exp(-1 / ((sr * attackMs) / 1000));
114
+ const releaseCoeff = Math.exp(-1 / ((sr * releaseMs) / 1000));
115
+ const thresholdLin = Math.pow(10, thresholdDb / 20);
116
+ let envelope = 0;
117
+ for (let i = 0; i < ch.length; i++) {
118
+ const absVal = Math.abs(ch[i]);
119
+ if (absVal > envelope) {
120
+ envelope = attackCoeff * envelope + (1 - attackCoeff) * absVal;
121
+ }
122
+ else {
123
+ envelope = releaseCoeff * envelope + (1 - releaseCoeff) * absVal;
124
+ }
125
+ if (envelope > thresholdLin) {
126
+ const dbOver = 20 * Math.log10(envelope / thresholdLin);
127
+ const dbReduction = dbOver * (1 - 1 / ratio);
128
+ const gainReduction = Math.pow(10, -dbReduction / 20);
129
+ out[i] = ch[i] * gainReduction;
130
+ }
131
+ else {
132
+ out[i] = ch[i];
133
+ }
134
+ }
135
+ return out;
136
+ });
137
+ return {
138
+ output: audioRefFromWav(encodeWav(result.samples, result.sampleRate, result.numChannels))
139
+ };
140
+ }
141
+ }
142
+ __decorate([
143
+ prop({
144
+ type: "audio",
145
+ default: {
146
+ type: "audio",
147
+ uri: "",
148
+ asset_id: null,
149
+ data: null,
150
+ metadata: null
151
+ },
152
+ title: "Audio",
153
+ description: "The audio file to process."
154
+ })
155
+ ], CompressNode.prototype, "audio", void 0);
156
+ __decorate([
157
+ prop({
158
+ type: "float",
159
+ default: -20,
160
+ title: "Threshold",
161
+ description: "Threshold in dB above which compression is applied.",
162
+ min: -60,
163
+ max: 0
164
+ })
165
+ ], CompressNode.prototype, "threshold", void 0);
166
+ __decorate([
167
+ prop({
168
+ type: "float",
169
+ default: 4,
170
+ title: "Ratio",
171
+ description: "Compression ratio. Higher values result in more compression.",
172
+ min: 1,
173
+ max: 20
174
+ })
175
+ ], CompressNode.prototype, "ratio", void 0);
176
+ __decorate([
177
+ prop({
178
+ type: "float",
179
+ default: 5,
180
+ title: "Attack",
181
+ description: "Attack time in milliseconds.",
182
+ min: 0.1,
183
+ max: 100
184
+ })
185
+ ], CompressNode.prototype, "attack", void 0);
186
+ __decorate([
187
+ prop({
188
+ type: "float",
189
+ default: 50,
190
+ title: "Release",
191
+ description: "Release time in milliseconds.",
192
+ min: 5,
193
+ max: 1000
194
+ })
195
+ ], CompressNode.prototype, "release", void 0);
196
+ // ── Distortion ────────────────────────────────────────────────────
197
+ export class DistortionNode extends BaseNode {
198
+ static nodeType = "lib.audio.Distortion";
199
+ static title = "Distortion";
200
+ static description = "Applies a distortion effect to an audio file.\n audio, effect, distortion\n\n Use cases:\n - Add grit and character to instruments\n - Create aggressive sound effects\n - Simulate overdriven amplifiers";
201
+ static metadataOutputTypes = {
202
+ output: "audio"
203
+ };
204
+ async process() {
205
+ const audio = (this.audio ?? {});
206
+ const driveDb = Number(this.drive_db ?? 25);
207
+ if (!audio.data)
208
+ return { output: audio };
209
+ const wav = decodeWav(audio);
210
+ const drive = Math.pow(10, driveDb / 20);
211
+ const result = processPerChannel(wav, (ch) => {
212
+ const out = new Float32Array(ch.length);
213
+ for (let i = 0; i < ch.length; i++) {
214
+ const driven = ch[i] * drive;
215
+ out[i] = (2 / Math.PI) * Math.atan(driven);
216
+ }
217
+ return out;
218
+ });
219
+ return {
220
+ output: audioRefFromWav(encodeWav(result.samples, result.sampleRate, result.numChannels))
221
+ };
222
+ }
223
+ }
224
+ __decorate([
225
+ prop({
226
+ type: "audio",
227
+ default: {
228
+ type: "audio",
229
+ uri: "",
230
+ asset_id: null,
231
+ data: null,
232
+ metadata: null
233
+ },
234
+ title: "Audio",
235
+ description: "The audio file to process."
236
+ })
237
+ ], DistortionNode.prototype, "audio", void 0);
238
+ __decorate([
239
+ prop({
240
+ type: "float",
241
+ default: 25,
242
+ title: "Drive Db",
243
+ description: "Amount of distortion to apply in decibels.",
244
+ min: 0,
245
+ max: 100
246
+ })
247
+ ], DistortionNode.prototype, "drive_db", void 0);
248
+ // ── Limiter ───────────────────────────────────────────────────────
249
+ export class LimiterNode extends BaseNode {
250
+ static nodeType = "lib.audio.Limiter";
251
+ static title = "Limiter";
252
+ static description = "Applies a limiter effect to an audio file.\n audio, effect, dynamics\n\n Use cases:\n - Prevent audio clipping\n - Increase perceived loudness without distortion\n - Control dynamic range of audio";
253
+ static metadataOutputTypes = {
254
+ output: "audio"
255
+ };
256
+ async process() {
257
+ const audio = (this.audio ?? {});
258
+ const thresholdDb = Number(this.threshold_db ?? -2);
259
+ const releaseMs = Number(this.release_ms ?? 250);
260
+ if (!audio.data)
261
+ return { output: audio };
262
+ const wav = decodeWav(audio);
263
+ const threshold = Math.pow(10, thresholdDb / 20);
264
+ const result = processPerChannel(wav, (ch, sr) => {
265
+ const out = new Float32Array(ch.length);
266
+ const releaseCoeff = Math.exp(-1 / ((sr * releaseMs) / 1000));
267
+ let gainReduction = 1;
268
+ for (let i = 0; i < ch.length; i++) {
269
+ const absVal = Math.abs(ch[i]);
270
+ if (absVal > threshold) {
271
+ const targetGain = threshold / absVal;
272
+ if (targetGain < gainReduction) {
273
+ gainReduction = targetGain;
274
+ }
275
+ }
276
+ else {
277
+ gainReduction =
278
+ releaseCoeff * gainReduction + (1 - releaseCoeff) * 1.0;
279
+ }
280
+ out[i] = ch[i] * gainReduction;
281
+ }
282
+ return out;
283
+ });
284
+ return {
285
+ output: audioRefFromWav(encodeWav(result.samples, result.sampleRate, result.numChannels))
286
+ };
287
+ }
288
+ }
289
+ __decorate([
290
+ prop({
291
+ type: "audio",
292
+ default: {
293
+ type: "audio",
294
+ uri: "",
295
+ asset_id: null,
296
+ data: null,
297
+ metadata: null
298
+ },
299
+ title: "Audio",
300
+ description: "The audio file to process."
301
+ })
302
+ ], LimiterNode.prototype, "audio", void 0);
303
+ __decorate([
304
+ prop({
305
+ type: "float",
306
+ default: -2,
307
+ title: "Threshold Db",
308
+ description: "Threshold in dB above which the limiter is applied.",
309
+ min: -60,
310
+ max: 0
311
+ })
312
+ ], LimiterNode.prototype, "threshold_db", void 0);
313
+ __decorate([
314
+ prop({
315
+ type: "float",
316
+ default: 250,
317
+ title: "Release Ms",
318
+ description: "Release time in milliseconds.",
319
+ min: 1,
320
+ max: 1000
321
+ })
322
+ ], LimiterNode.prototype, "release_ms", void 0);
323
+ // ── Reverb (Schroeder) ───────────────────────────────────────────
324
+ export class ReverbNode extends BaseNode {
325
+ static nodeType = "lib.audio.Reverb";
326
+ static title = "Reverb";
327
+ static description = "Applies a reverb effect to an audio file.\n audio, effect, reverb\n\n Use cases:\n - Add spatial depth to dry recordings\n - Simulate different room acoustics\n - Create atmospheric sound effects";
328
+ static metadataOutputTypes = {
329
+ output: "audio"
330
+ };
331
+ async process() {
332
+ const audio = (this.audio ?? {});
333
+ const roomScale = Number(this.room_scale ?? 0.5);
334
+ const damping = Number(this.damping ?? 0.5);
335
+ const wetLevel = Number(this.wet_level ?? 0.15);
336
+ const dryLevel = Number(this.dry_level ?? 0.5);
337
+ if (!audio.data)
338
+ return { output: audio };
339
+ const wav = decodeWav(audio);
340
+ const result = processPerChannel(wav, (ch, sr) => {
341
+ // Schroeder reverb: 4 parallel comb filters -> 2 series allpass filters
342
+ const baseCombDelays = [1557, 1617, 1491, 1422];
343
+ const baseAllpassDelays = [225, 556];
344
+ const scale = sr / 44100;
345
+ // Comb filter
346
+ function combFilter(input, delaySamples, feedback, damp) {
347
+ const out = new Float32Array(input.length);
348
+ const buf = new Float32Array(delaySamples);
349
+ let bufIdx = 0;
350
+ let filterStore = 0;
351
+ for (let i = 0; i < input.length; i++) {
352
+ const delayed = buf[bufIdx];
353
+ filterStore = delayed * (1 - damp) + filterStore * damp;
354
+ buf[bufIdx] = input[i] + filterStore * feedback;
355
+ out[i] = delayed;
356
+ bufIdx = (bufIdx + 1) % delaySamples;
357
+ }
358
+ return out;
359
+ }
360
+ // Allpass filter
361
+ function allpassFilter(input, delaySamples, feedback) {
362
+ const out = new Float32Array(input.length);
363
+ const buf = new Float32Array(delaySamples);
364
+ let bufIdx = 0;
365
+ for (let i = 0; i < input.length; i++) {
366
+ const delayed = buf[bufIdx];
367
+ buf[bufIdx] = input[i] + delayed * feedback;
368
+ out[i] = delayed - input[i] * feedback;
369
+ bufIdx = (bufIdx + 1) % delaySamples;
370
+ }
371
+ return out;
372
+ }
373
+ const feedback = roomScale * 0.28 + 0.7;
374
+ // Sum comb filters
375
+ const combOut = new Float32Array(ch.length);
376
+ for (const baseDelay of baseCombDelays) {
377
+ const delay = Math.round(baseDelay * scale);
378
+ const filtered = combFilter(ch, delay, feedback, damping);
379
+ for (let i = 0; i < ch.length; i++) {
380
+ combOut[i] += filtered[i];
381
+ }
382
+ }
383
+ // Series allpass filters
384
+ let apOut = combOut;
385
+ for (const baseDelay of baseAllpassDelays) {
386
+ const delay = Math.round(baseDelay * scale);
387
+ apOut = allpassFilter(apOut, delay, 0.5);
388
+ }
389
+ // Mix dry/wet
390
+ const out = new Float32Array(ch.length);
391
+ for (let i = 0; i < ch.length; i++) {
392
+ out[i] = ch[i] * dryLevel + apOut[i] * wetLevel;
393
+ }
394
+ return out;
395
+ });
396
+ return {
397
+ output: audioRefFromWav(encodeWav(result.samples, result.sampleRate, result.numChannels))
398
+ };
399
+ }
400
+ }
401
+ __decorate([
402
+ prop({
403
+ type: "audio",
404
+ default: {
405
+ type: "audio",
406
+ uri: "",
407
+ asset_id: null,
408
+ data: null,
409
+ metadata: null
410
+ },
411
+ title: "Audio",
412
+ description: "The audio file to process."
413
+ })
414
+ ], ReverbNode.prototype, "audio", void 0);
415
+ __decorate([
416
+ prop({
417
+ type: "float",
418
+ default: 0.5,
419
+ title: "Room Scale",
420
+ description: "Size of the simulated room. Higher values create larger spaces.",
421
+ min: 0,
422
+ max: 1
423
+ })
424
+ ], ReverbNode.prototype, "room_scale", void 0);
425
+ __decorate([
426
+ prop({
427
+ type: "float",
428
+ default: 0.5,
429
+ title: "Damping",
430
+ description: "Amount of high frequency absorption. Higher values create a duller sound.",
431
+ min: 0,
432
+ max: 1
433
+ })
434
+ ], ReverbNode.prototype, "damping", void 0);
435
+ __decorate([
436
+ prop({
437
+ type: "float",
438
+ default: 0.15,
439
+ title: "Wet Level",
440
+ description: "Level of the reverb effect in the output.",
441
+ min: 0,
442
+ max: 1
443
+ })
444
+ ], ReverbNode.prototype, "wet_level", void 0);
445
+ __decorate([
446
+ prop({
447
+ type: "float",
448
+ default: 0.5,
449
+ title: "Dry Level",
450
+ description: "Level of the original signal in the output.",
451
+ min: 0,
452
+ max: 1
453
+ })
454
+ ], ReverbNode.prototype, "dry_level", void 0);
455
+ // ── PitchShift (rubberband WASM) ─────────────────────────────────
456
+ export class PitchShiftNode extends BaseNode {
457
+ static nodeType = "lib.audio.PitchShift";
458
+ static title = "Pitch Shift";
459
+ static description = "Shifts the pitch of an audio file without changing its duration.\n audio, effect, pitch\n\n Use cases:\n - Transpose audio to a different key\n - Create harmonies or vocal effects\n - Adjust instrument tuning";
460
+ static metadataOutputTypes = {
461
+ output: "audio"
462
+ };
463
+ async process() {
464
+ const audio = (this.audio ?? {});
465
+ const semitones = Number(this.semitones ?? 0);
466
+ if (!audio.data)
467
+ return { output: audio };
468
+ if (semitones === 0) {
469
+ return { output: audio };
470
+ }
471
+ const { createRubberbandWrapper } = await import("@k13engineering/rubberband");
472
+ const wav = decodeWav(audio);
473
+ const { samples, sampleRate, numChannels } = wav;
474
+ const frameSamples = Math.floor(samples.length / numChannels);
475
+ const CHUNK_SIZE = 8192;
476
+ const rb = createRubberbandWrapper({
477
+ sampleRate,
478
+ channelCount: numChannels,
479
+ maxBufferSizeInFrames: CHUNK_SIZE,
480
+ options: {
481
+ processMode: "realtime",
482
+ engineMode: "finer",
483
+ pitchMode: "highquality"
484
+ }
485
+ });
486
+ rb.requestPitchScale({ pitchScale: Math.pow(2, semitones / 12) });
487
+ // Deinterleave into per-channel planes
488
+ const planes = [];
489
+ for (let ch = 0; ch < numChannels; ch++) {
490
+ const plane = new Float32Array(frameSamples);
491
+ for (let i = 0; i < frameSamples; i++) {
492
+ plane[i] = samples[i * numChannels + ch];
493
+ }
494
+ planes.push(plane);
495
+ }
496
+ // Process in chunks, collecting output
497
+ const outputParts = [];
498
+ const collectAvailable = () => {
499
+ let avail = rb.available();
500
+ while (avail > 0) {
501
+ const count = Math.min(avail, CHUNK_SIZE);
502
+ outputParts.push(rb.retrieve({ sampleCount: count }).planes);
503
+ avail = rb.available();
504
+ }
505
+ };
506
+ for (let offset = 0; offset < frameSamples; offset += CHUNK_SIZE) {
507
+ const end = Math.min(offset + CHUNK_SIZE, frameSamples);
508
+ const chunkPlanes = planes.map((p) => p.slice(offset, end));
509
+ rb.process({ audioData: { planes: chunkPlanes } });
510
+ collectAvailable();
511
+ }
512
+ rb.end();
513
+ collectAvailable();
514
+ // Concatenate output per channel
515
+ const totalOutFrames = outputParts.reduce((s, p) => s + p[0].length, 0);
516
+ const outPlanes = [];
517
+ for (let ch = 0; ch < numChannels; ch++) {
518
+ const plane = new Float32Array(totalOutFrames);
519
+ let pos = 0;
520
+ for (const part of outputParts) {
521
+ plane.set(part[ch], pos);
522
+ pos += part[ch].length;
523
+ }
524
+ outPlanes.push(plane);
525
+ }
526
+ // Trim processing latency — pitch shift preserves duration
527
+ const latency = rb.latencyInSamples();
528
+ const trimStart = Math.min(latency, totalOutFrames);
529
+ const trimEnd = Math.min(trimStart + frameSamples, totalOutFrames);
530
+ const outFrames = trimEnd - trimStart;
531
+ // Re-interleave trimmed output
532
+ const outSamples = new Float32Array(outFrames * numChannels);
533
+ for (let i = 0; i < outFrames; i++) {
534
+ for (let ch = 0; ch < numChannels; ch++) {
535
+ outSamples[i * numChannels + ch] = outPlanes[ch][trimStart + i];
536
+ }
537
+ }
538
+ return {
539
+ output: audioRefFromWav(encodeWav(outSamples, sampleRate, numChannels))
540
+ };
541
+ }
542
+ }
543
+ __decorate([
544
+ prop({
545
+ type: "audio",
546
+ default: {
547
+ type: "audio",
548
+ uri: "",
549
+ asset_id: null,
550
+ data: null,
551
+ metadata: null
552
+ },
553
+ title: "Audio",
554
+ description: "The audio file to process."
555
+ })
556
+ ], PitchShiftNode.prototype, "audio", void 0);
557
+ __decorate([
558
+ prop({
559
+ type: "float",
560
+ default: 0,
561
+ title: "Semitones",
562
+ description: "Number of semitones to shift the pitch. Positive values shift up, negative values shift down.",
563
+ min: -12,
564
+ max: 12
565
+ })
566
+ ], PitchShiftNode.prototype, "semitones", void 0);
567
+ // ── TimeStretch (rubberband WASM) ────────────────────────────────
568
+ export class TimeStretchNode extends BaseNode {
569
+ static nodeType = "lib.audio.TimeStretch";
570
+ static title = "Time Stretch";
571
+ static description = "Changes the speed of an audio file without altering its pitch.\n audio, transform, time\n\n Use cases:\n - Adjust audio duration to fit video length\n - Create slow-motion or fast-motion audio effects\n - Synchronize audio tracks of different lengths";
572
+ static metadataOutputTypes = {
573
+ output: "audio"
574
+ };
575
+ async process() {
576
+ const audio = (this.audio ?? {});
577
+ const rate = Number(this.rate ?? 1.0);
578
+ if (!audio.data)
579
+ return { output: audio };
580
+ if (rate === 1.0) {
581
+ return { output: audio };
582
+ }
583
+ const { createRubberbandWrapper } = await import("@k13engineering/rubberband");
584
+ const wav = decodeWav(audio);
585
+ const { samples, sampleRate, numChannels } = wav;
586
+ const frameSamples = Math.floor(samples.length / numChannels);
587
+ const CHUNK_SIZE = 8192;
588
+ const rb = createRubberbandWrapper({
589
+ sampleRate,
590
+ channelCount: numChannels,
591
+ maxBufferSizeInFrames: CHUNK_SIZE,
592
+ options: {
593
+ processMode: "realtime",
594
+ engineMode: "finer"
595
+ }
596
+ });
597
+ // Rubber Band timeRatio = output_duration / input_duration
598
+ // rate > 1 means faster (shorter output), so timeRatio = 1 / rate
599
+ rb.requestTimeRatio({ timeRatio: 1 / rate });
600
+ // Deinterleave into per-channel planes
601
+ const planes = [];
602
+ for (let ch = 0; ch < numChannels; ch++) {
603
+ const plane = new Float32Array(frameSamples);
604
+ for (let i = 0; i < frameSamples; i++) {
605
+ plane[i] = samples[i * numChannels + ch];
606
+ }
607
+ planes.push(plane);
608
+ }
609
+ // Process in chunks, collecting output
610
+ const outputParts = [];
611
+ const collectAvailable = () => {
612
+ let avail = rb.available();
613
+ while (avail > 0) {
614
+ const count = Math.min(avail, CHUNK_SIZE);
615
+ outputParts.push(rb.retrieve({ sampleCount: count }).planes);
616
+ avail = rb.available();
617
+ }
618
+ };
619
+ for (let offset = 0; offset < frameSamples; offset += CHUNK_SIZE) {
620
+ const end = Math.min(offset + CHUNK_SIZE, frameSamples);
621
+ const chunkPlanes = planes.map((p) => p.slice(offset, end));
622
+ rb.process({ audioData: { planes: chunkPlanes } });
623
+ collectAvailable();
624
+ }
625
+ rb.end();
626
+ collectAvailable();
627
+ // Concatenate output per channel
628
+ const totalOutFrames = outputParts.reduce((s, p) => s + p[0].length, 0);
629
+ const outPlanes = [];
630
+ for (let ch = 0; ch < numChannels; ch++) {
631
+ const plane = new Float32Array(totalOutFrames);
632
+ let pos = 0;
633
+ for (const part of outputParts) {
634
+ plane.set(part[ch], pos);
635
+ pos += part[ch].length;
636
+ }
637
+ outPlanes.push(plane);
638
+ }
639
+ // Trim processing latency — expected output = input / rate
640
+ const latency = rb.latencyInSamples();
641
+ const expectedFrames = Math.round(frameSamples / rate);
642
+ const trimStart = Math.min(latency, totalOutFrames);
643
+ const trimEnd = Math.min(trimStart + expectedFrames, totalOutFrames);
644
+ const outFrames = trimEnd - trimStart;
645
+ // Re-interleave trimmed output
646
+ const outSamples = new Float32Array(outFrames * numChannels);
647
+ for (let i = 0; i < outFrames; i++) {
648
+ for (let ch = 0; ch < numChannels; ch++) {
649
+ outSamples[i * numChannels + ch] = outPlanes[ch][trimStart + i];
650
+ }
651
+ }
652
+ return {
653
+ output: audioRefFromWav(encodeWav(outSamples, sampleRate, numChannels))
654
+ };
655
+ }
656
+ }
657
+ __decorate([
658
+ prop({
659
+ type: "audio",
660
+ default: {
661
+ type: "audio",
662
+ uri: "",
663
+ asset_id: null,
664
+ data: null,
665
+ metadata: null
666
+ },
667
+ title: "Audio",
668
+ description: "The audio file to process."
669
+ })
670
+ ], TimeStretchNode.prototype, "audio", void 0);
671
+ __decorate([
672
+ prop({
673
+ type: "float",
674
+ default: 1,
675
+ title: "Rate",
676
+ description: "Time stretch factor. Values > 1 speed up, < 1 slow down.",
677
+ min: 0.5,
678
+ max: 2
679
+ })
680
+ ], TimeStretchNode.prototype, "rate", void 0);
681
+ // ── NoiseGate ─────────────────────────────────────────────────────
682
+ export class NoiseGateNode extends BaseNode {
683
+ static nodeType = "lib.audio.NoiseGate";
684
+ static title = "Noise Gate";
685
+ static description = "Applies a noise gate effect to an audio file.\n audio, effect, dynamics\n\n Use cases:\n - Reduce background noise in recordings\n - Clean up audio tracks with unwanted low-level sounds\n - Create rhythmic effects by gating sustained sounds";
686
+ static metadataOutputTypes = {
687
+ output: "audio"
688
+ };
689
+ async process() {
690
+ const audio = (this.audio ?? {});
691
+ const thresholdDb = Number(this.threshold_db ?? -50);
692
+ const attackMs = Math.max(0.1, Number(this.attack_ms ?? 1));
693
+ const releaseMs = Math.max(1, Number(this.release_ms ?? 100));
694
+ if (!audio.data)
695
+ return { output: audio };
696
+ const wav = decodeWav(audio);
697
+ const thresholdLin = Math.pow(10, thresholdDb / 20);
698
+ const result = processPerChannel(wav, (ch, sr) => {
699
+ const out = new Float32Array(ch.length);
700
+ const attackCoeff = Math.exp(-1 / ((sr * attackMs) / 1000));
701
+ const releaseCoeff = Math.exp(-1 / ((sr * releaseMs) / 1000));
702
+ let envelope = 0;
703
+ let gain = 0;
704
+ for (let i = 0; i < ch.length; i++) {
705
+ const absVal = Math.abs(ch[i]);
706
+ // Envelope follower: fast attack, slow release
707
+ if (absVal > envelope) {
708
+ envelope = attackCoeff * envelope + (1 - attackCoeff) * absVal;
709
+ }
710
+ else {
711
+ envelope = releaseCoeff * envelope + (1 - releaseCoeff) * absVal;
712
+ }
713
+ // Gate: open when above threshold, close when below
714
+ const targetGain = envelope >= thresholdLin ? 1 : 0;
715
+ gain = releaseCoeff * gain + (1 - releaseCoeff) * targetGain;
716
+ out[i] = ch[i] * gain;
717
+ }
718
+ return out;
719
+ });
720
+ return {
721
+ output: audioRefFromWav(encodeWav(result.samples, result.sampleRate, result.numChannels))
722
+ };
723
+ }
724
+ }
725
+ __decorate([
726
+ prop({
727
+ type: "audio",
728
+ default: {
729
+ type: "audio",
730
+ uri: "",
731
+ asset_id: null,
732
+ data: null,
733
+ metadata: null
734
+ },
735
+ title: "Audio",
736
+ description: "The audio file to process."
737
+ })
738
+ ], NoiseGateNode.prototype, "audio", void 0);
739
+ __decorate([
740
+ prop({
741
+ type: "float",
742
+ default: -50,
743
+ title: "Threshold Db",
744
+ description: "Threshold in dB below which the gate is active.",
745
+ min: -90,
746
+ max: 0
747
+ })
748
+ ], NoiseGateNode.prototype, "threshold_db", void 0);
749
+ __decorate([
750
+ prop({
751
+ type: "float",
752
+ default: 1,
753
+ title: "Attack Ms",
754
+ description: "Attack time in milliseconds.",
755
+ min: 0.1,
756
+ max: 100
757
+ })
758
+ ], NoiseGateNode.prototype, "attack_ms", void 0);
759
+ __decorate([
760
+ prop({
761
+ type: "float",
762
+ default: 100,
763
+ title: "Release Ms",
764
+ description: "Release time in milliseconds.",
765
+ min: 5,
766
+ max: 1000
767
+ })
768
+ ], NoiseGateNode.prototype, "release_ms", void 0);
769
+ // ── Phaser ────────────────────────────────────────────────────────
770
+ export class PhaserNode extends BaseNode {
771
+ static nodeType = "lib.audio.Phaser";
772
+ static title = "Phaser";
773
+ static description = "Applies a phaser effect to an audio file.\n audio, effect, modulation\n\n Use cases:\n - Create sweeping, swooshing sounds\n - Add movement to static sounds\n - Produce psychedelic or space-like effects";
774
+ static metadataOutputTypes = {
775
+ output: "audio"
776
+ };
777
+ async process() {
778
+ const audio = (this.audio ?? {});
779
+ const rateHz = Number(this.rate_hz ?? 1);
780
+ const depth = Number(this.depth ?? 0.5);
781
+ const centreFreqHz = Number(this.centre_frequency_hz ?? 1300);
782
+ const feedback = Number(this.feedback ?? 0);
783
+ const mix = Number(this.mix ?? 0.5);
784
+ if (!audio.data)
785
+ return { output: audio };
786
+ const wav = decodeWav(audio);
787
+ const result = processPerChannel(wav, (ch, sr) => {
788
+ const out = new Float32Array(ch.length);
789
+ // 4-stage first-order all-pass phaser
790
+ const numStages = 4;
791
+ // Delay buffers: x[n-1] and y[n-1] for each stage
792
+ const xPrev = new Float32Array(numStages);
793
+ const yPrev = new Float32Array(numStages);
794
+ // Feedback delay
795
+ let feedbackSample = 0;
796
+ let lfoPhase = 0;
797
+ const lfoIncrement = (2 * Math.PI * rateHz) / sr;
798
+ for (let i = 0; i < ch.length; i++) {
799
+ // LFO modulates centre frequency
800
+ const lfo = Math.sin(lfoPhase) * depth;
801
+ lfoPhase += lfoIncrement;
802
+ if (lfoPhase > 2 * Math.PI)
803
+ lfoPhase -= 2 * Math.PI;
804
+ // Modulated frequency (centre ± depth range)
805
+ const modFreq = Math.max(20, Math.min(sr / 2 - 1, centreFreqHz * (1 + lfo)));
806
+ const tanVal = Math.tan((Math.PI * modFreq) / sr);
807
+ const a = (tanVal - 1) / (tanVal + 1);
808
+ // Input with feedback
809
+ const signal = ch[i] + feedbackSample * feedback;
810
+ // Apply all-pass filter stages
811
+ let apOut = signal;
812
+ for (let s = 0; s < numStages; s++) {
813
+ const newOut = a * apOut + xPrev[s] - a * yPrev[s];
814
+ xPrev[s] = apOut;
815
+ yPrev[s] = newOut;
816
+ apOut = newOut;
817
+ }
818
+ feedbackSample = apOut;
819
+ // Mix dry and wet
820
+ out[i] = ch[i] * (1 - mix) + apOut * mix;
821
+ }
822
+ return out;
823
+ });
824
+ return {
825
+ output: audioRefFromWav(encodeWav(result.samples, result.sampleRate, result.numChannels))
826
+ };
827
+ }
828
+ }
829
+ __decorate([
830
+ prop({
831
+ type: "audio",
832
+ default: {
833
+ type: "audio",
834
+ uri: "",
835
+ asset_id: null,
836
+ data: null,
837
+ metadata: null
838
+ },
839
+ title: "Audio",
840
+ description: "The audio file to process."
841
+ })
842
+ ], PhaserNode.prototype, "audio", void 0);
843
+ __decorate([
844
+ prop({
845
+ type: "float",
846
+ default: 1,
847
+ title: "Rate Hz",
848
+ description: "Rate of the phaser effect in Hz.",
849
+ min: 0.1,
850
+ max: 10
851
+ })
852
+ ], PhaserNode.prototype, "rate_hz", void 0);
853
+ __decorate([
854
+ prop({
855
+ type: "float",
856
+ default: 0.5,
857
+ title: "Depth",
858
+ description: "Depth of the phaser effect.",
859
+ min: 0,
860
+ max: 1
861
+ })
862
+ ], PhaserNode.prototype, "depth", void 0);
863
+ __decorate([
864
+ prop({
865
+ type: "float",
866
+ default: 1300,
867
+ title: "Centre Frequency Hz",
868
+ description: "Centre frequency of the phaser in Hz.",
869
+ min: 100,
870
+ max: 5000
871
+ })
872
+ ], PhaserNode.prototype, "centre_frequency_hz", void 0);
873
+ __decorate([
874
+ prop({
875
+ type: "float",
876
+ default: 0,
877
+ title: "Feedback",
878
+ description: "Feedback of the phaser effect. Negative values invert the phase.",
879
+ min: -1,
880
+ max: 1
881
+ })
882
+ ], PhaserNode.prototype, "feedback", void 0);
883
+ __decorate([
884
+ prop({
885
+ type: "float",
886
+ default: 0.5,
887
+ title: "Mix",
888
+ description: "Mix between the dry (original) and wet (effected) signals.",
889
+ min: 0,
890
+ max: 1
891
+ })
892
+ ], PhaserNode.prototype, "mix", void 0);
893
+ // ── Export ────────────────────────────────────────────────────────
894
+ export const LIB_PEDALBOARD_EXTRA_NODES = [
895
+ BitcrushNode,
896
+ CompressNode,
897
+ DistortionNode,
898
+ LimiterNode,
899
+ ReverbNode,
900
+ PitchShiftNode,
901
+ TimeStretchNode,
902
+ NoiseGateNode,
903
+ PhaserNode
904
+ ];
905
+ //# sourceMappingURL=lib-audio-effects.js.map