@drop-ai/core 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/README.md +655 -237
  2. package/dist/actions/ActionRegistry.d.ts.map +1 -1
  3. package/dist/actions/ActionRegistry.js +7 -2
  4. package/dist/actions/ActionRegistry.js.map +1 -1
  5. package/dist/actions/types.d.ts +7 -1
  6. package/dist/actions/types.d.ts.map +1 -1
  7. package/dist/analysis/AudioAnalyzer.d.ts +71 -0
  8. package/dist/analysis/AudioAnalyzer.d.ts.map +1 -0
  9. package/dist/analysis/AudioAnalyzer.js +569 -0
  10. package/dist/analysis/AudioAnalyzer.js.map +1 -0
  11. package/dist/audio/AudioEngine.d.ts +14 -1
  12. package/dist/audio/AudioEngine.d.ts.map +1 -1
  13. package/dist/audio/AudioEngine.js +115 -35
  14. package/dist/audio/AudioEngine.js.map +1 -1
  15. package/dist/audio/Auditioner.d.ts +104 -0
  16. package/dist/audio/Auditioner.d.ts.map +1 -0
  17. package/dist/audio/Auditioner.js +239 -0
  18. package/dist/audio/Auditioner.js.map +1 -0
  19. package/dist/audio/BWFMetadata.d.ts +116 -0
  20. package/dist/audio/BWFMetadata.d.ts.map +1 -0
  21. package/dist/audio/BWFMetadata.js +394 -0
  22. package/dist/audio/BWFMetadata.js.map +1 -0
  23. package/dist/audio/ChannelSplitter.d.ts +37 -0
  24. package/dist/audio/ChannelSplitter.d.ts.map +1 -0
  25. package/dist/audio/ChannelSplitter.js +82 -0
  26. package/dist/audio/ChannelSplitter.js.map +1 -0
  27. package/dist/audio/ExportAnalyzer.d.ts +39 -0
  28. package/dist/audio/ExportAnalyzer.d.ts.map +1 -0
  29. package/dist/audio/ExportAnalyzer.js +76 -0
  30. package/dist/audio/ExportAnalyzer.js.map +1 -0
  31. package/dist/audio/LufsNormalizer.d.ts +37 -0
  32. package/dist/audio/LufsNormalizer.d.ts.map +1 -0
  33. package/dist/audio/LufsNormalizer.js +217 -0
  34. package/dist/audio/LufsNormalizer.js.map +1 -0
  35. package/dist/audio/OfflineExporter.d.ts +1 -6
  36. package/dist/audio/OfflineExporter.d.ts.map +1 -1
  37. package/dist/audio/OfflineExporter.js +31 -10
  38. package/dist/audio/OfflineExporter.js.map +1 -1
  39. package/dist/audio/RoutingGraph.d.ts +134 -0
  40. package/dist/audio/RoutingGraph.d.ts.map +1 -0
  41. package/dist/audio/RoutingGraph.js +547 -0
  42. package/dist/audio/RoutingGraph.js.map +1 -0
  43. package/dist/audio/SampleRateConverter.d.ts +21 -0
  44. package/dist/audio/SampleRateConverter.d.ts.map +1 -0
  45. package/dist/audio/SampleRateConverter.js +84 -0
  46. package/dist/audio/SampleRateConverter.js.map +1 -0
  47. package/dist/audio/SilencePadding.d.ts +29 -0
  48. package/dist/audio/SilencePadding.d.ts.map +1 -0
  49. package/dist/audio/SilencePadding.js +86 -0
  50. package/dist/audio/SilencePadding.js.map +1 -0
  51. package/dist/audio/SourceCache.d.ts +13 -16
  52. package/dist/audio/SourceCache.d.ts.map +1 -1
  53. package/dist/audio/SourceCache.js +21 -33
  54. package/dist/audio/SourceCache.js.map +1 -1
  55. package/dist/audio/engine/Declick.d.ts +98 -0
  56. package/dist/audio/engine/Declick.d.ts.map +1 -0
  57. package/dist/audio/engine/Declick.js +204 -0
  58. package/dist/audio/engine/Declick.js.map +1 -0
  59. package/dist/audio/engine/DiskIO.d.ts +172 -0
  60. package/dist/audio/engine/DiskIO.d.ts.map +1 -0
  61. package/dist/audio/engine/DiskIO.js +384 -0
  62. package/dist/audio/engine/DiskIO.js.map +1 -0
  63. package/dist/audio/engine/LatencyCompensator.d.ts +46 -0
  64. package/dist/audio/engine/LatencyCompensator.d.ts.map +1 -0
  65. package/dist/audio/engine/LatencyCompensator.js +84 -0
  66. package/dist/audio/engine/LatencyCompensator.js.map +1 -0
  67. package/dist/audio/engine/MultiTrackRecorder.d.ts +146 -0
  68. package/dist/audio/engine/MultiTrackRecorder.d.ts.map +1 -0
  69. package/dist/audio/engine/MultiTrackRecorder.js +359 -0
  70. package/dist/audio/engine/MultiTrackRecorder.js.map +1 -0
  71. package/dist/audio/engine/PlaylistEngine.d.ts.map +1 -1
  72. package/dist/audio/engine/PlaylistEngine.js +9 -2
  73. package/dist/audio/engine/PlaylistEngine.js.map +1 -1
  74. package/dist/audio/engine/PunchRecordManager.d.ts +113 -0
  75. package/dist/audio/engine/PunchRecordManager.d.ts.map +1 -0
  76. package/dist/audio/engine/PunchRecordManager.js +191 -0
  77. package/dist/audio/engine/PunchRecordManager.js.map +1 -0
  78. package/dist/audio/engine/RoutingGraph.d.ts +135 -0
  79. package/dist/audio/engine/RoutingGraph.d.ts.map +1 -0
  80. package/dist/audio/engine/RoutingGraph.js +436 -0
  81. package/dist/audio/engine/RoutingGraph.js.map +1 -0
  82. package/dist/audio/engine/SidechainRouter.d.ts +139 -0
  83. package/dist/audio/engine/SidechainRouter.d.ts.map +1 -0
  84. package/dist/audio/engine/SidechainRouter.js +292 -0
  85. package/dist/audio/engine/SidechainRouter.js.map +1 -0
  86. package/dist/audio/engine/XrunTracker.d.ts +71 -0
  87. package/dist/audio/engine/XrunTracker.d.ts.map +1 -0
  88. package/dist/audio/engine/XrunTracker.js +118 -0
  89. package/dist/audio/engine/XrunTracker.js.map +1 -0
  90. package/dist/audio/export/CDMarkerExporter.d.ts +62 -0
  91. package/dist/audio/export/CDMarkerExporter.d.ts.map +1 -0
  92. package/dist/audio/export/CDMarkerExporter.js +164 -0
  93. package/dist/audio/export/CDMarkerExporter.js.map +1 -0
  94. package/dist/audio/export/ExportGraphBuilder.d.ts +121 -0
  95. package/dist/audio/export/ExportGraphBuilder.d.ts.map +1 -0
  96. package/dist/audio/export/ExportGraphBuilder.js +522 -0
  97. package/dist/audio/export/ExportGraphBuilder.js.map +1 -0
  98. package/dist/audio/export/ExportPresetManager.d.ts +87 -0
  99. package/dist/audio/export/ExportPresetManager.d.ts.map +1 -0
  100. package/dist/audio/export/ExportPresetManager.js +306 -0
  101. package/dist/audio/export/ExportPresetManager.js.map +1 -0
  102. package/dist/commands/handlers/RegionHandler.d.ts.map +1 -1
  103. package/dist/commands/handlers/RegionHandler.js +25 -1
  104. package/dist/commands/handlers/RegionHandler.js.map +1 -1
  105. package/dist/commands/handlers/TrackHandler.js +1 -1
  106. package/dist/commands/handlers/TrackHandler.js.map +1 -1
  107. package/dist/commands/impl/FreezeTrackCommand.d.ts.map +1 -1
  108. package/dist/commands/impl/FreezeTrackCommand.js +37 -36
  109. package/dist/commands/impl/FreezeTrackCommand.js.map +1 -1
  110. package/dist/commands/impl/SetRegionTimeDomainCommand.d.ts.map +1 -1
  111. package/dist/commands/impl/SetRegionTimeDomainCommand.js +3 -3
  112. package/dist/commands/impl/SetRegionTimeDomainCommand.js.map +1 -1
  113. package/dist/commands/impl/ToggleLoopCommand.d.ts +1 -0
  114. package/dist/commands/impl/ToggleLoopCommand.d.ts.map +1 -1
  115. package/dist/commands/impl/ToggleLoopCommand.js +10 -0
  116. package/dist/commands/impl/ToggleLoopCommand.js.map +1 -1
  117. package/dist/commands/impl/TrimRegionCommand.d.ts +14 -1
  118. package/dist/commands/impl/TrimRegionCommand.d.ts.map +1 -1
  119. package/dist/commands/impl/TrimRegionCommand.js +138 -33
  120. package/dist/commands/impl/TrimRegionCommand.js.map +1 -1
  121. package/dist/commands/impl/TrimRegionToPlayheadCommand.d.ts +27 -0
  122. package/dist/commands/impl/TrimRegionToPlayheadCommand.d.ts.map +1 -0
  123. package/dist/commands/impl/TrimRegionToPlayheadCommand.js +69 -0
  124. package/dist/commands/impl/TrimRegionToPlayheadCommand.js.map +1 -0
  125. package/dist/commands/impl/TrimRegionToRangeCommand.d.ts +28 -0
  126. package/dist/commands/impl/TrimRegionToRangeCommand.d.ts.map +1 -0
  127. package/dist/commands/impl/TrimRegionToRangeCommand.js +69 -0
  128. package/dist/commands/impl/TrimRegionToRangeCommand.js.map +1 -0
  129. package/dist/commands/impl/TrimToAdjacentRegionCommand.d.ts +27 -0
  130. package/dist/commands/impl/TrimToAdjacentRegionCommand.d.ts.map +1 -0
  131. package/dist/commands/impl/TrimToAdjacentRegionCommand.js +77 -0
  132. package/dist/commands/impl/TrimToAdjacentRegionCommand.js.map +1 -0
  133. package/dist/commands/types.d.ts +19 -0
  134. package/dist/commands/types.d.ts.map +1 -1
  135. package/dist/commands/types.js +21 -0
  136. package/dist/commands/types.js.map +1 -1
  137. package/dist/domain/Crossfade.d.ts +78 -0
  138. package/dist/domain/Crossfade.d.ts.map +1 -0
  139. package/dist/domain/Crossfade.js +216 -0
  140. package/dist/domain/Crossfade.js.map +1 -0
  141. package/dist/domain/ExportConfig.d.ts +98 -1
  142. package/dist/domain/ExportConfig.d.ts.map +1 -1
  143. package/dist/domain/ExportConfig.js +154 -1
  144. package/dist/domain/ExportConfig.js.map +1 -1
  145. package/dist/domain/ExportPreset.d.ts +62 -0
  146. package/dist/domain/ExportPreset.d.ts.map +1 -0
  147. package/dist/domain/ExportPreset.js +79 -0
  148. package/dist/domain/ExportPreset.js.map +1 -0
  149. package/dist/domain/ImportStatus.d.ts +40 -0
  150. package/dist/domain/ImportStatus.d.ts.map +1 -0
  151. package/dist/domain/ImportStatus.js +86 -0
  152. package/dist/domain/ImportStatus.js.map +1 -0
  153. package/dist/domain/Playlist.d.ts +72 -0
  154. package/dist/domain/Playlist.d.ts.map +1 -1
  155. package/dist/domain/Playlist.js +231 -6
  156. package/dist/domain/Playlist.js.map +1 -1
  157. package/dist/domain/Region.d.ts +76 -0
  158. package/dist/domain/Region.d.ts.map +1 -1
  159. package/dist/domain/Region.js +234 -1
  160. package/dist/domain/Region.js.map +1 -1
  161. package/dist/domain/Route.d.ts +43 -3
  162. package/dist/domain/Route.d.ts.map +1 -1
  163. package/dist/domain/Route.js +92 -6
  164. package/dist/domain/Route.js.map +1 -1
  165. package/dist/domain/Session.d.ts +31 -0
  166. package/dist/domain/Session.d.ts.map +1 -1
  167. package/dist/domain/Session.js +70 -0
  168. package/dist/domain/Session.js.map +1 -1
  169. package/dist/domain/Source.d.ts +145 -1
  170. package/dist/domain/Source.d.ts.map +1 -1
  171. package/dist/domain/Source.js +144 -1
  172. package/dist/domain/Source.js.map +1 -1
  173. package/dist/domain/ThawList.d.ts +37 -0
  174. package/dist/domain/ThawList.d.ts.map +1 -0
  175. package/dist/domain/ThawList.js +73 -0
  176. package/dist/domain/ThawList.js.map +1 -0
  177. package/dist/domain/Track.d.ts +93 -1
  178. package/dist/domain/Track.d.ts.map +1 -1
  179. package/dist/domain/Track.js +136 -0
  180. package/dist/domain/Track.js.map +1 -1
  181. package/dist/domain/TriggerBox.d.ts +123 -0
  182. package/dist/domain/TriggerBox.d.ts.map +1 -0
  183. package/dist/domain/TriggerBox.js +430 -0
  184. package/dist/domain/TriggerBox.js.map +1 -0
  185. package/dist/domain/VCATrack.d.ts +64 -1
  186. package/dist/domain/VCATrack.d.ts.map +1 -1
  187. package/dist/domain/VCATrack.js +128 -1
  188. package/dist/domain/VCATrack.js.map +1 -1
  189. package/dist/domain/VideoExportConfig.d.ts +117 -0
  190. package/dist/domain/VideoExportConfig.d.ts.map +1 -0
  191. package/dist/domain/VideoExportConfig.js +244 -0
  192. package/dist/domain/VideoExportConfig.js.map +1 -0
  193. package/dist/domain/VideoExportStatus.d.ts +89 -0
  194. package/dist/domain/VideoExportStatus.d.ts.map +1 -0
  195. package/dist/domain/VideoExportStatus.js +192 -0
  196. package/dist/domain/VideoExportStatus.js.map +1 -0
  197. package/dist/domain/VideoMetadata.d.ts +46 -0
  198. package/dist/domain/VideoMetadata.d.ts.map +1 -0
  199. package/dist/domain/VideoMetadata.js +2 -0
  200. package/dist/domain/VideoMetadata.js.map +1 -0
  201. package/dist/domain/index.d.ts +5 -0
  202. package/dist/domain/index.d.ts.map +1 -1
  203. package/dist/domain/index.js +5 -0
  204. package/dist/domain/index.js.map +1 -1
  205. package/dist/domain/temporal/TempoMap.d.ts +199 -2
  206. package/dist/domain/temporal/TempoMap.d.ts.map +1 -1
  207. package/dist/domain/temporal/TempoMap.js +464 -30
  208. package/dist/domain/temporal/TempoMap.js.map +1 -1
  209. package/dist/index.d.ts +43 -1
  210. package/dist/index.d.ts.map +1 -1
  211. package/dist/index.js +32 -1
  212. package/dist/index.js.map +1 -1
  213. package/dist/lib/ThawList.d.ts +100 -0
  214. package/dist/lib/ThawList.d.ts.map +1 -0
  215. package/dist/lib/ThawList.js +153 -0
  216. package/dist/lib/ThawList.js.map +1 -0
  217. package/dist/midi/MidiFileParser.d.ts +33 -0
  218. package/dist/midi/MidiFileParser.d.ts.map +1 -0
  219. package/dist/midi/MidiFileParser.js +246 -0
  220. package/dist/midi/MidiFileParser.js.map +1 -0
  221. package/dist/midi/MidiFileWriter.d.ts +31 -0
  222. package/dist/midi/MidiFileWriter.d.ts.map +1 -0
  223. package/dist/midi/MidiFileWriter.js +160 -0
  224. package/dist/midi/MidiFileWriter.js.map +1 -0
  225. package/dist/midi/MidiImporter.d.ts +37 -0
  226. package/dist/midi/MidiImporter.d.ts.map +1 -0
  227. package/dist/midi/MidiImporter.js +62 -0
  228. package/dist/midi/MidiImporter.js.map +1 -0
  229. package/dist/plugins/PluginPresetManager.d.ts +86 -0
  230. package/dist/plugins/PluginPresetManager.d.ts.map +1 -0
  231. package/dist/plugins/PluginPresetManager.js +140 -0
  232. package/dist/plugins/PluginPresetManager.js.map +1 -0
  233. package/dist/processing/IO.d.ts +15 -1
  234. package/dist/processing/IO.d.ts.map +1 -1
  235. package/dist/processing/IO.js +29 -1
  236. package/dist/processing/IO.js.map +1 -1
  237. package/dist/processing/InternalSend.d.ts +104 -0
  238. package/dist/processing/InternalSend.d.ts.map +1 -0
  239. package/dist/processing/InternalSend.js +175 -0
  240. package/dist/processing/InternalSend.js.map +1 -0
  241. package/dist/processing/MeterDSP.d.ts +166 -0
  242. package/dist/processing/MeterDSP.d.ts.map +1 -0
  243. package/dist/processing/MeterDSP.js +754 -0
  244. package/dist/processing/MeterDSP.js.map +1 -0
  245. package/dist/processing/Panner.d.ts +145 -0
  246. package/dist/processing/Panner.d.ts.map +1 -0
  247. package/dist/processing/Panner.js +281 -0
  248. package/dist/processing/Panner.js.map +1 -0
  249. package/dist/processing/PluginInsert.d.ts +56 -1
  250. package/dist/processing/PluginInsert.d.ts.map +1 -1
  251. package/dist/processing/PluginInsert.js +180 -2
  252. package/dist/processing/PluginInsert.js.map +1 -1
  253. package/dist/processing/Processor.d.ts +38 -0
  254. package/dist/processing/Processor.d.ts.map +1 -1
  255. package/dist/processing/Processor.js +60 -1
  256. package/dist/processing/Processor.js.map +1 -1
  257. package/dist/processing/SurroundPanner.d.ts +122 -0
  258. package/dist/processing/SurroundPanner.d.ts.map +1 -0
  259. package/dist/processing/SurroundPanner.js +376 -0
  260. package/dist/processing/SurroundPanner.js.map +1 -0
  261. package/dist/processing/TruePeakLimiter.d.ts +34 -0
  262. package/dist/processing/TruePeakLimiter.d.ts.map +1 -0
  263. package/dist/processing/TruePeakLimiter.js +144 -0
  264. package/dist/processing/TruePeakLimiter.js.map +1 -0
  265. package/dist/storage/ExportPresetStorage.d.ts +33 -0
  266. package/dist/storage/ExportPresetStorage.d.ts.map +1 -0
  267. package/dist/storage/ExportPresetStorage.js +121 -0
  268. package/dist/storage/ExportPresetStorage.js.map +1 -0
  269. package/dist/storage/SessionArchive.d.ts +73 -0
  270. package/dist/storage/SessionArchive.d.ts.map +1 -0
  271. package/dist/storage/SessionArchive.js +211 -0
  272. package/dist/storage/SessionArchive.js.map +1 -0
  273. package/dist/storage/SessionTemplate.d.ts +74 -5
  274. package/dist/storage/SessionTemplate.d.ts.map +1 -1
  275. package/dist/storage/SessionTemplate.js +247 -53
  276. package/dist/storage/SessionTemplate.js.map +1 -1
  277. package/dist/utils/BwfMetadataWriter.d.ts +42 -0
  278. package/dist/utils/BwfMetadataWriter.d.ts.map +1 -0
  279. package/dist/utils/BwfMetadataWriter.js +131 -0
  280. package/dist/utils/BwfMetadataWriter.js.map +1 -0
  281. package/dist/utils/FilenameTemplate.d.ts +40 -0
  282. package/dist/utils/FilenameTemplate.d.ts.map +1 -0
  283. package/dist/utils/FilenameTemplate.js +78 -0
  284. package/dist/utils/FilenameTemplate.js.map +1 -0
  285. package/dist/utils/Logger.d.ts +28 -0
  286. package/dist/utils/Logger.d.ts.map +1 -0
  287. package/dist/utils/Logger.js +46 -0
  288. package/dist/utils/Logger.js.map +1 -0
  289. package/dist/utils/Mp4ChapterGenerator.d.ts +17 -0
  290. package/dist/utils/Mp4ChapterGenerator.d.ts.map +1 -0
  291. package/dist/utils/Mp4ChapterGenerator.js +33 -0
  292. package/dist/utils/Mp4ChapterGenerator.js.map +1 -0
  293. package/dist/utils/OggEncoder.d.ts +20 -20
  294. package/dist/utils/OggEncoder.d.ts.map +1 -1
  295. package/dist/utils/OggEncoder.js +114 -50
  296. package/dist/utils/OggEncoder.js.map +1 -1
  297. package/dist/utils/TocGenerator.d.ts +17 -0
  298. package/dist/utils/TocGenerator.d.ts.map +1 -0
  299. package/dist/utils/TocGenerator.js +47 -0
  300. package/dist/utils/TocGenerator.js.map +1 -0
  301. package/package.json +7 -8
@@ -0,0 +1,376 @@
1
+ import { Processor } from './Processor';
2
+ import { Signal } from '../lib/Signal';
3
+ /**
4
+ * SurroundPanner supports multichannel panning beyond stereo.
5
+ *
6
+ * Ardour reference: libs/ardour/surround_pannable.cc
7
+ *
8
+ * Supported layouts:
9
+ * - Stereo (2.0): L, R
10
+ * - Quad (4.0): FL, FR, RL, RR
11
+ * - 5.1: FL, FR, C, LFE, RL, RR
12
+ * - 7.1: FL, FR, C, LFE, RL, RR, SL, SR
13
+ * - Atmos/3D: adds height channels
14
+ *
15
+ * Uses VBAP (Vector Base Amplitude Panning) algorithm for
16
+ * arbitrary speaker configurations.
17
+ */
18
+ export var SpeakerLayout;
19
+ (function (SpeakerLayout) {
20
+ SpeakerLayout["STEREO"] = "STEREO";
21
+ SpeakerLayout["QUAD"] = "QUAD";
22
+ SpeakerLayout["SURROUND_5_1"] = "5.1";
23
+ SpeakerLayout["SURROUND_7_1"] = "7.1";
24
+ })(SpeakerLayout || (SpeakerLayout = {}));
25
+ export class SurroundPanner extends Processor {
26
+ constructor(id, layout) {
27
+ super(id, 'Surround Panner');
28
+ this._azimuth = 0; // Source horizontal angle in degrees
29
+ this._elevation = 0; // Source vertical angle in degrees
30
+ this._spread = 0; // Source spread (0 = point, 1 = omni)
31
+ this._lfeLevel = 0; // LFE send level (0-1)
32
+ this._layout = SpeakerLayout.STEREO;
33
+ this._speakers = [];
34
+ this._gains = new Float32Array(0);
35
+ this.positionChanged = new Signal();
36
+ this.layoutChanged = new Signal();
37
+ const initialLayout = layout !== null && layout !== void 0 ? layout : SpeakerLayout.STEREO;
38
+ this._speakers = this.setupSpeakers(initialLayout);
39
+ this._layout = initialLayout;
40
+ this._gains = new Float32Array(this._speakers.length);
41
+ this.computeGains();
42
+ }
43
+ // ── Position control ────────────────────────────────────────────────────
44
+ /**
45
+ * Set the source position.
46
+ * @param azimuth Horizontal angle in degrees (-180 to 180).
47
+ * @param elevation Vertical angle in degrees (-90 to 90). Defaults to current.
48
+ */
49
+ setPosition(azimuth, elevation) {
50
+ const clampedAz = Math.max(-180, Math.min(180, azimuth));
51
+ const clampedEl = elevation !== undefined
52
+ ? Math.max(-90, Math.min(90, elevation))
53
+ : this._elevation;
54
+ if (this._azimuth !== clampedAz || this._elevation !== clampedEl) {
55
+ this._azimuth = clampedAz;
56
+ this._elevation = clampedEl;
57
+ this.computeGains();
58
+ this.positionChanged.emit({ azimuth: this._azimuth, elevation: this._elevation });
59
+ this.stateChanged.emit();
60
+ }
61
+ }
62
+ /**
63
+ * Set the source spread.
64
+ * @param spread 0 = point source, 1 = omnidirectional.
65
+ */
66
+ setSpread(spread) {
67
+ const clamped = Math.max(0, Math.min(1, spread));
68
+ if (this._spread !== clamped) {
69
+ this._spread = clamped;
70
+ this.computeGains();
71
+ this.stateChanged.emit();
72
+ }
73
+ }
74
+ /**
75
+ * Set the LFE send level.
76
+ * @param level 0 to 1.
77
+ */
78
+ setLFELevel(level) {
79
+ const clamped = Math.max(0, Math.min(1, level));
80
+ if (this._lfeLevel !== clamped) {
81
+ this._lfeLevel = clamped;
82
+ this.stateChanged.emit();
83
+ }
84
+ }
85
+ get azimuth() { return this._azimuth; }
86
+ get elevation() { return this._elevation; }
87
+ get spread() { return this._spread; }
88
+ get lfeLevel() { return this._lfeLevel; }
89
+ // ── Layout ──────────────────────────────────────────────────────────────
90
+ /**
91
+ * Set the speaker layout. Recomputes speaker positions and gains.
92
+ */
93
+ setLayout(layout) {
94
+ if (this._layout !== layout) {
95
+ this._layout = layout;
96
+ this._speakers = this.setupSpeakers(layout);
97
+ this._gains = new Float32Array(this._speakers.length);
98
+ this.computeGains();
99
+ this.layoutChanged.emit(layout);
100
+ this.stateChanged.emit();
101
+ }
102
+ }
103
+ get layout() { return this._layout; }
104
+ /** Number of output channels for the current layout. */
105
+ get channelCount() { return this._speakers.length; }
106
+ /** Speaker positions for the current layout. */
107
+ get speakers() { return this._speakers; }
108
+ // ── Gain computation ────────────────────────────────────────────────────
109
+ /**
110
+ * Compute per-channel gains based on the current source position,
111
+ * spread, and layout using VBAP.
112
+ *
113
+ * @returns Float32Array of linear gains, one per speaker/channel.
114
+ */
115
+ computeGains() {
116
+ const hasElevation = this._elevation !== 0;
117
+ let rawGains;
118
+ if (hasElevation) {
119
+ rawGains = this.vbap3D(this._azimuth, this._elevation);
120
+ }
121
+ else {
122
+ rawGains = this.vbap2D(this._azimuth);
123
+ }
124
+ // Apply spread: interpolate between point-source gains and uniform (omni)
125
+ if (this._spread > 0) {
126
+ const uniformGain = 1.0 / Math.sqrt(this._speakers.length);
127
+ for (let i = 0; i < rawGains.length; i++) {
128
+ rawGains[i] = rawGains[i] * (1 - this._spread) + uniformGain * this._spread;
129
+ }
130
+ }
131
+ // For 5.1 and 7.1 layouts, apply LFE level to the LFE channel
132
+ if (this._layout === SpeakerLayout.SURROUND_5_1 || this._layout === SpeakerLayout.SURROUND_7_1) {
133
+ const lfeIndex = this.getLFEChannelIndex();
134
+ if (lfeIndex >= 0 && lfeIndex < rawGains.length) {
135
+ rawGains[lfeIndex] = this._lfeLevel;
136
+ }
137
+ }
138
+ // Store and return
139
+ this._gains = rawGains;
140
+ return new Float32Array(rawGains);
141
+ }
142
+ // ── VBAP algorithms ─────────────────────────────────────────────────────
143
+ /**
144
+ * 2D VBAP: Vector Base Amplitude Panning in the horizontal plane.
145
+ *
146
+ * For each adjacent speaker pair, computes the amplitude split
147
+ * based on the angular position of the source relative to both speakers.
148
+ *
149
+ * @param azimuth Source azimuth in degrees (-180 to 180).
150
+ */
151
+ vbap2D(azimuth) {
152
+ const gains = new Float32Array(this._speakers.length);
153
+ const speakerCount = this._speakers.length;
154
+ if (speakerCount === 0)
155
+ return gains;
156
+ // Special case: stereo uses simple equal-power panning
157
+ if (this._layout === SpeakerLayout.STEREO) {
158
+ // Normalize azimuth: -180..180 -> -1..1 for L/R
159
+ const normalized = Math.max(-1, Math.min(1, azimuth / 180));
160
+ const pan01 = (normalized + 1) / 2; // 0 = left, 1 = right
161
+ const angle = pan01 * Math.PI / 2;
162
+ gains[0] = Math.cos(angle); // Left
163
+ gains[1] = Math.sin(angle); // Right
164
+ return gains;
165
+ }
166
+ // Convert source azimuth to radians
167
+ const sourceRad = (azimuth * Math.PI) / 180;
168
+ // Get non-LFE speaker indices and their azimuths
169
+ const activeSpeakers = [];
170
+ for (let i = 0; i < speakerCount; i++) {
171
+ // Skip LFE channel in VBAP calculations
172
+ if (this._speakers[i].label === 'LFE')
173
+ continue;
174
+ activeSpeakers.push({
175
+ index: i,
176
+ azimuthRad: (this._speakers[i].azimuth * Math.PI) / 180,
177
+ });
178
+ }
179
+ // Sort speakers by azimuth
180
+ activeSpeakers.sort((a, b) => a.azimuthRad - b.azimuthRad);
181
+ if (activeSpeakers.length === 0)
182
+ return gains;
183
+ if (activeSpeakers.length === 1) {
184
+ gains[activeSpeakers[0].index] = 1.0;
185
+ return gains;
186
+ }
187
+ // Find the two speakers that bracket the source angle
188
+ let found = false;
189
+ for (let i = 0; i < activeSpeakers.length; i++) {
190
+ const next = (i + 1) % activeSpeakers.length;
191
+ let az1 = activeSpeakers[i].azimuthRad;
192
+ let az2 = activeSpeakers[next].azimuthRad;
193
+ // Handle wrap-around
194
+ let span = az2 - az1;
195
+ if (span <= 0)
196
+ span += 2 * Math.PI;
197
+ let sourceOffset = sourceRad - az1;
198
+ if (sourceOffset < 0)
199
+ sourceOffset += 2 * Math.PI;
200
+ if (sourceOffset <= span) {
201
+ // Source is between speakers i and next
202
+ const t = span > 0 ? sourceOffset / span : 0;
203
+ // Equal-power crossfade between the two speakers
204
+ const angle = t * Math.PI / 2;
205
+ const g2 = Math.sin(angle);
206
+ const g1 = Math.cos(angle);
207
+ gains[activeSpeakers[i].index] = g1;
208
+ gains[activeSpeakers[next].index] = g2;
209
+ found = true;
210
+ break;
211
+ }
212
+ }
213
+ // Fallback: if no pair found, use closest speaker
214
+ if (!found) {
215
+ let minDist = Infinity;
216
+ let closest = 0;
217
+ for (const sp of activeSpeakers) {
218
+ let dist = Math.abs(sourceRad - sp.azimuthRad);
219
+ if (dist > Math.PI)
220
+ dist = 2 * Math.PI - dist;
221
+ if (dist < minDist) {
222
+ minDist = dist;
223
+ closest = sp.index;
224
+ }
225
+ }
226
+ gains[closest] = 1.0;
227
+ }
228
+ return gains;
229
+ }
230
+ /**
231
+ * 3D VBAP: Vector Base Amplitude Panning with elevation.
232
+ *
233
+ * Extends 2D VBAP by considering the vertical angle to distribute
234
+ * energy across speakers at different elevations.
235
+ *
236
+ * @param azimuth Source azimuth in degrees.
237
+ * @param elevation Source elevation in degrees.
238
+ */
239
+ vbap3D(azimuth, elevation) {
240
+ const gains = new Float32Array(this._speakers.length);
241
+ const speakerCount = this._speakers.length;
242
+ if (speakerCount === 0)
243
+ return gains;
244
+ // Convert source position to Cartesian unit vector
245
+ const srcAzRad = (azimuth * Math.PI) / 180;
246
+ const srcElRad = (elevation * Math.PI) / 180;
247
+ const srcX = Math.cos(srcElRad) * Math.cos(srcAzRad);
248
+ const srcY = Math.cos(srcElRad) * Math.sin(srcAzRad);
249
+ const srcZ = Math.sin(srcElRad);
250
+ // Compute dot product with each speaker's direction vector.
251
+ // This gives a measure of how "close" the source is to each speaker.
252
+ const dotProducts = [];
253
+ let totalWeight = 0;
254
+ for (let i = 0; i < speakerCount; i++) {
255
+ if (this._speakers[i].label === 'LFE') {
256
+ dotProducts.push(0);
257
+ continue;
258
+ }
259
+ const spAzRad = (this._speakers[i].azimuth * Math.PI) / 180;
260
+ const spElRad = (this._speakers[i].elevation * Math.PI) / 180;
261
+ const spX = Math.cos(spElRad) * Math.cos(spAzRad);
262
+ const spY = Math.cos(spElRad) * Math.sin(spAzRad);
263
+ const spZ = Math.sin(spElRad);
264
+ // Dot product (cosine of angle between source and speaker)
265
+ let dot = srcX * spX + srcY * spY + srcZ * spZ;
266
+ // Clamp to [0, 1] - speakers behind the source get no signal
267
+ dot = Math.max(0, dot);
268
+ // Square the dot product for sharper localization
269
+ dot = dot * dot;
270
+ dotProducts.push(dot);
271
+ totalWeight += dot;
272
+ }
273
+ // Normalize and apply
274
+ if (totalWeight > 0) {
275
+ for (let i = 0; i < speakerCount; i++) {
276
+ // Use sqrt for energy preservation (VBAP convention)
277
+ gains[i] = Math.sqrt(dotProducts[i] / totalWeight);
278
+ }
279
+ }
280
+ else {
281
+ // Fallback: equal distribution across all non-LFE speakers
282
+ let nonLfeCount = 0;
283
+ for (let i = 0; i < speakerCount; i++) {
284
+ if (this._speakers[i].label !== 'LFE')
285
+ nonLfeCount++;
286
+ }
287
+ if (nonLfeCount > 0) {
288
+ const equalGain = 1.0 / Math.sqrt(nonLfeCount);
289
+ for (let i = 0; i < speakerCount; i++) {
290
+ if (this._speakers[i].label !== 'LFE') {
291
+ gains[i] = equalGain;
292
+ }
293
+ }
294
+ }
295
+ }
296
+ return gains;
297
+ }
298
+ // ── Speaker setup ───────────────────────────────────────────────────────
299
+ /**
300
+ * Setup default speaker positions for a given layout.
301
+ * Angles follow the ITU-R BS.775 and ITU-R BS.2051 standards.
302
+ */
303
+ setupSpeakers(layout) {
304
+ switch (layout) {
305
+ case SpeakerLayout.STEREO:
306
+ return [
307
+ { azimuth: -30, elevation: 0, distance: 1, label: 'L' },
308
+ { azimuth: 30, elevation: 0, distance: 1, label: 'R' },
309
+ ];
310
+ case SpeakerLayout.QUAD:
311
+ return [
312
+ { azimuth: -45, elevation: 0, distance: 1, label: 'FL' },
313
+ { azimuth: 45, elevation: 0, distance: 1, label: 'FR' },
314
+ { azimuth: -135, elevation: 0, distance: 1, label: 'RL' },
315
+ { azimuth: 135, elevation: 0, distance: 1, label: 'RR' },
316
+ ];
317
+ case SpeakerLayout.SURROUND_5_1:
318
+ return [
319
+ { azimuth: -30, elevation: 0, distance: 1, label: 'FL' },
320
+ { azimuth: 30, elevation: 0, distance: 1, label: 'FR' },
321
+ { azimuth: 0, elevation: 0, distance: 1, label: 'C' },
322
+ { azimuth: 0, elevation: -90, distance: 1, label: 'LFE' },
323
+ { azimuth: -110, elevation: 0, distance: 1, label: 'RL' },
324
+ { azimuth: 110, elevation: 0, distance: 1, label: 'RR' },
325
+ ];
326
+ case SpeakerLayout.SURROUND_7_1:
327
+ return [
328
+ { azimuth: -30, elevation: 0, distance: 1, label: 'FL' },
329
+ { azimuth: 30, elevation: 0, distance: 1, label: 'FR' },
330
+ { azimuth: 0, elevation: 0, distance: 1, label: 'C' },
331
+ { azimuth: 0, elevation: -90, distance: 1, label: 'LFE' },
332
+ { azimuth: -135, elevation: 0, distance: 1, label: 'RL' },
333
+ { azimuth: 135, elevation: 0, distance: 1, label: 'RR' },
334
+ { azimuth: -90, elevation: 0, distance: 1, label: 'SL' },
335
+ { azimuth: 90, elevation: 0, distance: 1, label: 'SR' },
336
+ ];
337
+ default:
338
+ return [
339
+ { azimuth: -30, elevation: 0, distance: 1, label: 'L' },
340
+ { azimuth: 30, elevation: 0, distance: 1, label: 'R' },
341
+ ];
342
+ }
343
+ }
344
+ /**
345
+ * Get the index of the LFE channel in the current layout.
346
+ * Returns -1 if the layout has no LFE channel.
347
+ */
348
+ getLFEChannelIndex() {
349
+ return this._speakers.findIndex(s => s.label === 'LFE');
350
+ }
351
+ // ── Serialization ───────────────────────────────────────────────────────
352
+ toJSON() {
353
+ return {
354
+ id: this.id,
355
+ name: this.name,
356
+ azimuth: this._azimuth,
357
+ elevation: this._elevation,
358
+ spread: this._spread,
359
+ lfeLevel: this._lfeLevel,
360
+ layout: this._layout,
361
+ active: this.active,
362
+ };
363
+ }
364
+ static fromJSON(data) {
365
+ const panner = new SurroundPanner(data.id, data.layout);
366
+ panner.name = data.name;
367
+ panner._azimuth = data.azimuth;
368
+ panner._elevation = data.elevation;
369
+ panner._spread = data.spread;
370
+ panner._lfeLevel = data.lfeLevel;
371
+ panner.active = data.active;
372
+ panner.computeGains();
373
+ return panner;
374
+ }
375
+ }
376
+ //# sourceMappingURL=SurroundPanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SurroundPanner.js","sourceRoot":"","sources":["../../src/processing/SurroundPanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * True Peak Limiter
3
+ * Ardour reference: libs/ardour/ardour/export_format_specification.h
4
+ * (use_tp_limiter, normalize_dbtp fields)
5
+ *
6
+ * Implements:
7
+ * 1. 4x oversampling via windowed sinc interpolation
8
+ * 2. True peak measurement per ITU-R BS.1770-4 Annex 2
9
+ * 3. Brick-wall limiting with lookahead and release
10
+ */
11
+ /**
12
+ * Measure the true peak of a mono channel using 4x oversampling.
13
+ * Returns peak in linear scale.
14
+ */
15
+ export declare function measureTruePeak(samples: Float32Array): number;
16
+ /**
17
+ * Measure true peak in dBTP for a mono channel.
18
+ */
19
+ export declare function measureTruePeakDbTP(samples: Float32Array): number;
20
+ /**
21
+ * Apply brick-wall true peak limiting to an AudioBuffer.
22
+ * Modifies the buffer in-place.
23
+ *
24
+ * The limiter uses a simple gain reduction approach:
25
+ * 1. Find the true peak of the entire buffer
26
+ * 2. If it exceeds the ceiling, apply uniform gain reduction
27
+ * 3. For per-sample limiting, use a lookahead envelope follower
28
+ *
29
+ * @param buffer Audio buffer to limit (modified in-place)
30
+ * @param ceilingDbTP Target ceiling in dBTP (e.g., -1.0)
31
+ * @returns true if limiting was applied
32
+ */
33
+ export declare function applyTruePeakLimiter(buffer: AudioBuffer, ceilingDbTP?: number): boolean;
34
+ //# sourceMappingURL=TruePeakLimiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TruePeakLimiter.d.ts","sourceRoot":"","sources":["../../src/processing/TruePeakLimiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAqBH;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAwB7D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAGjE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,GAAE,MAAa,GAAG,OAAO,CA0E7F"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * True Peak Limiter
3
+ * Ardour reference: libs/ardour/ardour/export_format_specification.h
4
+ * (use_tp_limiter, normalize_dbtp fields)
5
+ *
6
+ * Implements:
7
+ * 1. 4x oversampling via windowed sinc interpolation
8
+ * 2. True peak measurement per ITU-R BS.1770-4 Annex 2
9
+ * 3. Brick-wall limiting with lookahead and release
10
+ */
11
+ /**
12
+ * 4x oversampling FIR coefficients (half-band low-pass, 12-tap).
13
+ * These approximate a windowed sinc interpolation filter for 4x upsampling.
14
+ */
15
+ const OVERSAMPLE_TAPS = [
16
+ 0.0017089843750,
17
+ -0.0291748046875,
18
+ -0.0189208984375,
19
+ 0.0708618164062,
20
+ 0.3031005859375,
21
+ 0.4736328125000,
22
+ 0.3031005859375,
23
+ 0.0708618164062,
24
+ -0.0189208984375,
25
+ -0.0291748046875,
26
+ 0.0017089843750,
27
+ 0.0000000000000,
28
+ ];
29
+ /**
30
+ * Measure the true peak of a mono channel using 4x oversampling.
31
+ * Returns peak in linear scale.
32
+ */
33
+ export function measureTruePeak(samples) {
34
+ const taps = OVERSAMPLE_TAPS;
35
+ const numTaps = taps.length;
36
+ const halfTaps = Math.floor(numTaps / 2);
37
+ let maxPeak = 0;
38
+ // For each input sample, compute 4 interpolated values
39
+ for (let i = 0; i < samples.length; i++) {
40
+ for (let phase = 0; phase < 4; phase++) {
41
+ let sum = 0;
42
+ for (let t = 0; t < numTaps; t++) {
43
+ const srcIdx = i - halfTaps + t;
44
+ if (srcIdx >= 0 && srcIdx < samples.length) {
45
+ // Phase-offset tap selection for polyphase decomposition
46
+ sum += samples[srcIdx] * taps[t];
47
+ }
48
+ }
49
+ const abs = Math.abs(sum);
50
+ if (abs > maxPeak)
51
+ maxPeak = abs;
52
+ }
53
+ }
54
+ return maxPeak;
55
+ }
56
+ /**
57
+ * Measure true peak in dBTP for a mono channel.
58
+ */
59
+ export function measureTruePeakDbTP(samples) {
60
+ const peak = measureTruePeak(samples);
61
+ return peak > 0 ? 20 * Math.log10(peak) : -Infinity;
62
+ }
63
+ /**
64
+ * Apply brick-wall true peak limiting to an AudioBuffer.
65
+ * Modifies the buffer in-place.
66
+ *
67
+ * The limiter uses a simple gain reduction approach:
68
+ * 1. Find the true peak of the entire buffer
69
+ * 2. If it exceeds the ceiling, apply uniform gain reduction
70
+ * 3. For per-sample limiting, use a lookahead envelope follower
71
+ *
72
+ * @param buffer Audio buffer to limit (modified in-place)
73
+ * @param ceilingDbTP Target ceiling in dBTP (e.g., -1.0)
74
+ * @returns true if limiting was applied
75
+ */
76
+ export function applyTruePeakLimiter(buffer, ceilingDbTP = -1.0) {
77
+ const ceilingLinear = Math.pow(10, ceilingDbTP / 20);
78
+ const numChannels = buffer.numberOfChannels;
79
+ // Measure true peak across all channels
80
+ let globalTruePeak = 0;
81
+ for (let ch = 0; ch < numChannels; ch++) {
82
+ const data = buffer.getChannelData(ch);
83
+ const peak = measureTruePeak(data);
84
+ if (peak > globalTruePeak)
85
+ globalTruePeak = peak;
86
+ }
87
+ // If already below ceiling, nothing to do
88
+ if (globalTruePeak <= ceilingLinear) {
89
+ return false;
90
+ }
91
+ // Lookahead limiter parameters
92
+ const sampleRate = buffer.sampleRate;
93
+ const lookaheadMs = 5; // 5ms lookahead
94
+ const releaseMs = 100; // 100ms release
95
+ const lookaheadSamples = Math.ceil(sampleRate * lookaheadMs / 1000);
96
+ const releaseCoeff = Math.exp(-1.0 / (sampleRate * releaseMs / 1000));
97
+ // Compute per-sample gain envelope based on peak detection
98
+ const length = buffer.length;
99
+ const gainEnvelope = new Float32Array(length);
100
+ gainEnvelope.fill(1.0);
101
+ // First pass: find per-sample peaks across channels
102
+ const peaks = new Float32Array(length);
103
+ for (let ch = 0; ch < numChannels; ch++) {
104
+ const data = buffer.getChannelData(ch);
105
+ for (let i = 0; i < length; i++) {
106
+ const abs = Math.abs(data[i]);
107
+ if (abs > peaks[i])
108
+ peaks[i] = abs;
109
+ }
110
+ }
111
+ // Second pass: compute gain reduction with lookahead
112
+ let currentGain = 1.0;
113
+ for (let i = length - 1; i >= 0; i--) {
114
+ // Look ahead to find the peak that's coming
115
+ let futureMax = 0;
116
+ const lookEnd = Math.min(i + lookaheadSamples, length);
117
+ for (let j = i; j < lookEnd; j++) {
118
+ if (peaks[j] > futureMax)
119
+ futureMax = peaks[j];
120
+ }
121
+ // Desired gain for this sample
122
+ let desiredGain = 1.0;
123
+ if (futureMax > ceilingLinear) {
124
+ desiredGain = ceilingLinear / futureMax;
125
+ }
126
+ // Smooth gain changes (attack = instant, release = smooth)
127
+ if (desiredGain < currentGain) {
128
+ currentGain = desiredGain; // instant attack
129
+ }
130
+ else {
131
+ currentGain = desiredGain + releaseCoeff * (currentGain - desiredGain);
132
+ }
133
+ gainEnvelope[i] = currentGain;
134
+ }
135
+ // Apply gain envelope to all channels
136
+ for (let ch = 0; ch < numChannels; ch++) {
137
+ const data = buffer.getChannelData(ch);
138
+ for (let i = 0; i < length; i++) {
139
+ data[i] *= gainEnvelope[i];
140
+ }
141
+ }
142
+ return true;
143
+ }
144
+ //# sourceMappingURL=TruePeakLimiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TruePeakLimiter.js","sourceRoot":"","sources":["../../src/processing/TruePeakLimiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { ExportPreset } from '../domain/ExportPreset';
2
+ /**
3
+ * IndexedDB storage for export presets.
4
+ * Follows the same pattern as SessionStorage.
5
+ */
6
+ export declare class ExportPresetStorage {
7
+ private static instance;
8
+ private dbPromise;
9
+ private constructor();
10
+ static getInstance(): ExportPresetStorage;
11
+ private openDB;
12
+ /**
13
+ * Save a user preset.
14
+ */
15
+ savePreset(preset: ExportPreset): Promise<void>;
16
+ /**
17
+ * Load a preset by ID.
18
+ */
19
+ loadPreset(id: string): Promise<ExportPreset | null>;
20
+ /**
21
+ * List all saved user presets.
22
+ */
23
+ listPresets(): Promise<ExportPreset[]>;
24
+ /**
25
+ * Get all presets (built-in + user).
26
+ */
27
+ getAllPresets(): Promise<ExportPreset[]>;
28
+ /**
29
+ * Delete a user preset by ID.
30
+ */
31
+ deletePreset(id: string): Promise<void>;
32
+ }
33
+ //# sourceMappingURL=ExportPresetStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExportPresetStorage.d.ts","sourceRoot":"","sources":["../../src/storage/ExportPresetStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,YAAY,EAAqB,MAAM,wBAAwB,CAAC;AAM/F;;;GAGG;AACH,qBAAa,mBAAmB;IAC5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAsB;IAC7C,OAAO,CAAC,SAAS,CAAqC;IAEtD,OAAO;WAEO,WAAW,IAAI,mBAAmB;IAOhD,OAAO,CAAC,MAAM;IA2Cd;;OAEG;IACU,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAY5D;;OAEG;IACU,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAajE;;OAEG;IACU,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAanD;;OAEG;IACU,aAAa,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAMrD;;OAEG;IACU,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CASvD"}