@libraz/libsonare 1.7.2 → 1.8.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 (303) hide show
  1. package/NOTICE +178 -0
  2. package/README.md +26 -203
  3. package/dist/_chain_config.d.ts +14 -0
  4. package/dist/_chain_config.d.ts.map +1 -0
  5. package/dist/_effects_common.d.ts +6 -0
  6. package/dist/_effects_common.d.ts.map +1 -0
  7. package/dist/_feature_validation.d.ts +8 -0
  8. package/dist/_feature_validation.d.ts.map +1 -0
  9. package/dist/_fft_options.d.ts +24 -0
  10. package/dist/_fft_options.d.ts.map +1 -0
  11. package/dist/align_take.d.ts +50 -0
  12. package/dist/align_take.d.ts.map +1 -0
  13. package/dist/analysis.d.ts +29 -5840
  14. package/dist/analysis.d.ts.map +1 -0
  15. package/dist/analysis.js +873 -722
  16. package/dist/analysis.js.map +1 -1
  17. package/dist/analysis_helpers.d.ts +9 -0
  18. package/dist/analysis_helpers.d.ts.map +1 -0
  19. package/dist/audio.d.ts +163 -0
  20. package/dist/audio.d.ts.map +1 -0
  21. package/dist/clip_page_streamer.d.ts +133 -0
  22. package/dist/clip_page_streamer.d.ts.map +1 -0
  23. package/dist/codes.d.ts +44 -0
  24. package/dist/codes.d.ts.map +1 -0
  25. package/dist/effects_mastering.d.ts +23 -0
  26. package/dist/effects_mastering.d.ts.map +1 -0
  27. package/dist/effects_note_ops.d.ts +477 -0
  28. package/dist/effects_note_ops.d.ts.map +1 -0
  29. package/dist/effects_percussive.d.ts +185 -0
  30. package/dist/effects_percussive.d.ts.map +1 -0
  31. package/dist/effects_separation.d.ts +65 -0
  32. package/dist/effects_separation.d.ts.map +1 -0
  33. package/dist/effects_spectral.d.ts +28 -0
  34. package/dist/effects_spectral.d.ts.map +1 -0
  35. package/dist/effects_timepitch.d.ts +129 -0
  36. package/dist/effects_timepitch.d.ts.map +1 -0
  37. package/dist/effects_voice_change.d.ts +53 -0
  38. package/dist/effects_voice_change.d.ts.map +1 -0
  39. package/dist/errors.d.ts +51 -0
  40. package/dist/errors.d.ts.map +1 -0
  41. package/dist/feature_core.d.ts +341 -0
  42. package/dist/feature_core.d.ts.map +1 -0
  43. package/dist/feature_decompose.d.ts +278 -0
  44. package/dist/feature_decompose.d.ts.map +1 -0
  45. package/dist/feature_inverse.d.ts +128 -0
  46. package/dist/feature_inverse.d.ts.map +1 -0
  47. package/dist/feature_loudness.d.ts +66 -0
  48. package/dist/feature_loudness.d.ts.map +1 -0
  49. package/dist/feature_music.d.ts +307 -0
  50. package/dist/feature_music.d.ts.map +1 -0
  51. package/dist/feature_pitch.d.ts +108 -0
  52. package/dist/feature_pitch.d.ts.map +1 -0
  53. package/dist/feature_resample.d.ts +16 -0
  54. package/dist/feature_resample.d.ts.map +1 -0
  55. package/dist/feature_spectral.d.ts +137 -0
  56. package/dist/feature_spectral.d.ts.map +1 -0
  57. package/dist/feature_spectrogram.d.ts +198 -0
  58. package/dist/feature_spectrogram.d.ts.map +1 -0
  59. package/dist/features.d.ts +10 -0
  60. package/dist/features.d.ts.map +1 -0
  61. package/dist/hrtf/default.shrf +0 -0
  62. package/dist/index.d.ts +74 -7431
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +3758 -1362
  65. package/dist/index.js.map +1 -1
  66. package/dist/instrument_types.d.ts +517 -0
  67. package/dist/instrument_types.d.ts.map +1 -0
  68. package/dist/live_audio.d.ts +35 -0
  69. package/dist/live_audio.d.ts.map +1 -0
  70. package/dist/mastering_chain.d.ts +213 -0
  71. package/dist/mastering_chain.d.ts.map +1 -0
  72. package/dist/mastering_core.d.ts +457 -0
  73. package/dist/mastering_core.d.ts.map +1 -0
  74. package/dist/mastering_dynamics.d.ts +80 -0
  75. package/dist/mastering_dynamics.d.ts.map +1 -0
  76. package/dist/metering.d.ts +287 -0
  77. package/dist/metering.d.ts.map +1 -0
  78. package/dist/mixer.d.ts +464 -0
  79. package/dist/mixer.d.ts.map +1 -0
  80. package/dist/mixing_assistant.d.ts +62 -0
  81. package/dist/mixing_assistant.d.ts.map +1 -0
  82. package/dist/mixing_oneshot.d.ts +40 -0
  83. package/dist/mixing_oneshot.d.ts.map +1 -0
  84. package/dist/module_state.d.ts +15 -0
  85. package/dist/module_state.d.ts.map +1 -0
  86. package/dist/opfs_clip_pages.d.ts +28 -0
  87. package/dist/opfs_clip_pages.d.ts.map +1 -0
  88. package/dist/playback_renderer.d.ts +128 -0
  89. package/dist/playback_renderer.d.ts.map +1 -0
  90. package/dist/polyphony.d.ts +202 -0
  91. package/dist/polyphony.d.ts.map +1 -0
  92. package/dist/project.d.ts +8 -0
  93. package/dist/project.d.ts.map +1 -0
  94. package/dist/project_class.d.ts +562 -0
  95. package/dist/project_class.d.ts.map +1 -0
  96. package/dist/project_internal.d.ts +194 -0
  97. package/dist/project_internal.d.ts.map +1 -0
  98. package/dist/project_synth.d.ts +74 -0
  99. package/dist/project_synth.d.ts.map +1 -0
  100. package/dist/project_types.d.ts +652 -0
  101. package/dist/project_types.d.ts.map +1 -0
  102. package/dist/public_types.d.ts +185 -0
  103. package/dist/public_types.d.ts.map +1 -0
  104. package/dist/public_types_acoustic.d.ts +215 -0
  105. package/dist/public_types_acoustic.d.ts.map +1 -0
  106. package/dist/public_types_mastering.d.ts +510 -0
  107. package/dist/public_types_mastering.d.ts.map +1 -0
  108. package/dist/public_types_mixing.d.ts +436 -0
  109. package/dist/public_types_mixing.d.ts.map +1 -0
  110. package/dist/public_types_music.d.ts +619 -0
  111. package/dist/public_types_music.d.ts.map +1 -0
  112. package/dist/public_types_playback.d.ts +164 -0
  113. package/dist/public_types_playback.d.ts.map +1 -0
  114. package/dist/public_types_realtime.d.ts +174 -0
  115. package/dist/public_types_realtime.d.ts.map +1 -0
  116. package/dist/public_types_repair.d.ts +424 -0
  117. package/dist/public_types_repair.d.ts.map +1 -0
  118. package/dist/public_types_spectral.d.ts +697 -0
  119. package/dist/public_types_spectral.d.ts.map +1 -0
  120. package/dist/quick_analysis.d.ts +445 -0
  121. package/dist/quick_analysis.d.ts.map +1 -0
  122. package/dist/realtime_engine.d.ts +850 -0
  123. package/dist/realtime_engine.d.ts.map +1 -0
  124. package/dist/realtime_voice_changer.d.ts +158 -0
  125. package/dist/realtime_voice_changer.d.ts.map +1 -0
  126. package/dist/repair_dereverb.d.ts +187 -0
  127. package/dist/repair_dereverb.d.ts.map +1 -0
  128. package/dist/repair_impulsive.d.ts +186 -0
  129. package/dist/repair_impulsive.d.ts.map +1 -0
  130. package/dist/repair_noise.d.ts +239 -0
  131. package/dist/repair_noise.d.ts.map +1 -0
  132. package/dist/repair_trim.d.ts +123 -0
  133. package/dist/repair_trim.d.ts.map +1 -0
  134. package/dist/sample_bank.d.ts +84 -0
  135. package/dist/sample_bank.d.ts.map +1 -0
  136. package/dist/scale.d.ts +10 -0
  137. package/dist/scale.d.ts.map +1 -0
  138. package/dist/schemas/mixer-scene.schema.json +393 -0
  139. package/dist/schemas/playback-renderer-config.schema.json +392 -0
  140. package/dist/sonare-analysis.d.ts +8 -0
  141. package/dist/sonare-analysis.js +2 -2
  142. package/dist/sonare-analysis.wasm +0 -0
  143. package/dist/sonare.d.ts +3909 -0
  144. package/dist/sonare.js +2 -2
  145. package/dist/sonare.wasm +0 -0
  146. package/dist/stream_analyzer.d.ts +163 -0
  147. package/dist/stream_analyzer.d.ts.map +1 -0
  148. package/dist/stream_types.d.ts +214 -0
  149. package/dist/stream_types.d.ts.map +1 -0
  150. package/dist/streaming_mixing.d.ts +6 -0
  151. package/dist/streaming_mixing.d.ts.map +1 -0
  152. package/dist/streaming_processors.d.ts +335 -0
  153. package/dist/streaming_processors.d.ts.map +1 -0
  154. package/dist/transcribe.d.ts +77 -0
  155. package/dist/transcribe.d.ts.map +1 -0
  156. package/dist/validation.d.ts +140 -0
  157. package/dist/validation.d.ts.map +1 -0
  158. package/dist/web_midi.d.ts +77 -0
  159. package/dist/web_midi.d.ts.map +1 -0
  160. package/dist/worker.d.ts +5 -48
  161. package/dist/worker.d.ts.map +1 -0
  162. package/dist/worker.js +94 -41
  163. package/dist/worker.js.map +1 -1
  164. package/dist/worker_client.d.ts +96 -0
  165. package/dist/worker_client.d.ts.map +1 -0
  166. package/dist/worker_protocol.d.ts +43 -0
  167. package/dist/worker_protocol.d.ts.map +1 -0
  168. package/dist/worklet/audio_types.d.ts +21 -0
  169. package/dist/worklet/audio_types.d.ts.map +1 -0
  170. package/dist/worklet/engine-automation.d.ts +29 -0
  171. package/dist/worklet/engine-automation.d.ts.map +1 -0
  172. package/dist/worklet/engine-capture-facade.d.ts +35 -0
  173. package/dist/worklet/engine-capture-facade.d.ts.map +1 -0
  174. package/dist/worklet/engine-clips.d.ts +23 -0
  175. package/dist/worklet/engine-clips.d.ts.map +1 -0
  176. package/dist/worklet/engine-markers.d.ts +40 -0
  177. package/dist/worklet/engine-markers.d.ts.map +1 -0
  178. package/dist/worklet/engine-mixer-facade.d.ts +128 -0
  179. package/dist/worklet/engine-mixer-facade.d.ts.map +1 -0
  180. package/dist/worklet/engine-node.d.ts +81 -0
  181. package/dist/worklet/engine-node.d.ts.map +1 -0
  182. package/dist/worklet/engine-offline.d.ts +81 -0
  183. package/dist/worklet/engine-offline.d.ts.map +1 -0
  184. package/dist/worklet/engine-options.d.ts +12 -0
  185. package/dist/worklet/engine-options.d.ts.map +1 -0
  186. package/dist/worklet/engine-parameter-facade.d.ts +106 -0
  187. package/dist/worklet/engine-parameter-facade.d.ts.map +1 -0
  188. package/dist/worklet/engine-processor.d.ts +68 -0
  189. package/dist/worklet/engine-processor.d.ts.map +1 -0
  190. package/dist/worklet/engine-register.d.ts +2 -0
  191. package/dist/worklet/engine-register.d.ts.map +1 -0
  192. package/dist/worklet/engine-strips.d.ts +73 -0
  193. package/dist/worklet/engine-strips.d.ts.map +1 -0
  194. package/dist/worklet/engine-sync.d.ts +37 -0
  195. package/dist/worklet/engine-sync.d.ts.map +1 -0
  196. package/dist/worklet/engine-tempo-facade.d.ts +48 -0
  197. package/dist/worklet/engine-tempo-facade.d.ts.map +1 -0
  198. package/dist/worklet/engine.d.ts +397 -0
  199. package/dist/worklet/engine.d.ts.map +1 -0
  200. package/dist/worklet/guards.d.ts +47 -0
  201. package/dist/worklet/guards.d.ts.map +1 -0
  202. package/dist/worklet/messages.d.ts +710 -0
  203. package/dist/worklet/messages.d.ts.map +1 -0
  204. package/dist/worklet/mixer-processor.d.ts +46 -0
  205. package/dist/worklet/mixer-processor.d.ts.map +1 -0
  206. package/dist/worklet/playback-processor.d.ts +62 -0
  207. package/dist/worklet/playback-processor.d.ts.map +1 -0
  208. package/dist/worklet/protocol.d.ts +323 -0
  209. package/dist/worklet/protocol.d.ts.map +1 -0
  210. package/dist/worklet/voice-changer-processor.d.ts +41 -0
  211. package/dist/worklet/voice-changer-processor.d.ts.map +1 -0
  212. package/dist/worklet.d.ts +16 -2515
  213. package/dist/worklet.d.ts.map +1 -0
  214. package/dist/worklet.js +2763 -501
  215. package/dist/worklet.js.map +1 -1
  216. package/package.json +23 -12
  217. package/src/_effects_common.ts +17 -0
  218. package/src/_feature_validation.ts +34 -0
  219. package/src/_fft_options.ts +39 -0
  220. package/src/align_take.ts +64 -0
  221. package/src/analysis.ts +56 -3
  222. package/src/analysis_helpers.ts +7 -0
  223. package/src/audio.ts +106 -3
  224. package/src/codes.ts +39 -2
  225. package/src/effects_mastering.ts +97 -22
  226. package/src/effects_note_ops.ts +635 -0
  227. package/src/effects_percussive.ts +217 -0
  228. package/src/effects_separation.ts +150 -0
  229. package/src/effects_spectral.ts +60 -0
  230. package/src/effects_timepitch.ts +377 -0
  231. package/src/errors.ts +23 -1
  232. package/src/feature_core.ts +127 -2
  233. package/src/feature_decompose.ts +633 -0
  234. package/src/feature_inverse.ts +454 -0
  235. package/src/feature_loudness.ts +125 -0
  236. package/src/feature_music.ts +107 -14
  237. package/src/feature_pitch.ts +96 -1
  238. package/src/feature_spectral.ts +16 -611
  239. package/src/feature_spectrogram.ts +63 -450
  240. package/src/features.ts +36 -22
  241. package/src/index.ts +282 -30
  242. package/src/instrument_types.ts +645 -0
  243. package/src/live_audio.ts +27 -1
  244. package/src/mastering_chain.ts +184 -0
  245. package/src/mastering_core.ts +346 -32
  246. package/src/mastering_dynamics.ts +22 -11
  247. package/src/metering.ts +67 -24
  248. package/src/mixer.ts +212 -3
  249. package/src/mixing_assistant.ts +138 -0
  250. package/src/mixing_oneshot.ts +10 -5
  251. package/src/module_state.ts +24 -2
  252. package/src/playback_renderer.ts +252 -0
  253. package/src/polyphony.ts +279 -0
  254. package/src/project.ts +61 -24
  255. package/src/project_class.ts +450 -27
  256. package/src/project_internal.ts +149 -42
  257. package/src/project_synth.ts +67 -1
  258. package/src/project_types.ts +268 -270
  259. package/src/public_types.ts +122 -3
  260. package/src/public_types_acoustic.ts +112 -3
  261. package/src/public_types_mastering.ts +254 -73
  262. package/src/public_types_mixing.ts +363 -1
  263. package/src/public_types_music.ts +312 -2
  264. package/src/public_types_playback.ts +195 -0
  265. package/src/public_types_realtime.ts +39 -7
  266. package/src/public_types_repair.ts +446 -0
  267. package/src/public_types_spectral.ts +487 -1
  268. package/src/quick_analysis.ts +203 -26
  269. package/src/realtime_engine.ts +711 -28
  270. package/src/realtime_voice_changer.ts +55 -1
  271. package/src/repair_dereverb.ts +299 -0
  272. package/src/repair_impulsive.ts +395 -0
  273. package/src/repair_noise.ts +425 -0
  274. package/src/repair_trim.ts +226 -0
  275. package/src/sample_bank.ts +113 -0
  276. package/src/sonare.js.d.ts +1122 -30
  277. package/src/stream_analyzer.ts +36 -4
  278. package/src/stream_types.ts +37 -0
  279. package/src/streaming_mixing.ts +1 -1
  280. package/src/streaming_processors.ts +194 -10
  281. package/src/transcribe.ts +89 -0
  282. package/src/validation.ts +285 -11
  283. package/src/web_midi.ts +1 -6
  284. package/src/worker.ts +18 -2
  285. package/src/worklet/audio_types.ts +37 -0
  286. package/src/worklet/engine-mixer-facade.ts +444 -10
  287. package/src/worklet/engine-node.ts +78 -26
  288. package/src/worklet/engine-offline.ts +14 -8
  289. package/src/worklet/engine-parameter-facade.ts +21 -0
  290. package/src/worklet/engine-processor.ts +272 -83
  291. package/src/worklet/engine-register.ts +32 -18
  292. package/src/worklet/engine-strips.ts +280 -9
  293. package/src/worklet/engine-sync.ts +14 -6
  294. package/src/worklet/engine.ts +365 -31
  295. package/src/worklet/guards.ts +140 -44
  296. package/src/worklet/messages.ts +227 -2
  297. package/src/worklet/mixer-processor.ts +109 -47
  298. package/src/worklet/playback-processor.ts +300 -0
  299. package/src/worklet/protocol.ts +53 -3
  300. package/src/worklet/voice-changer-processor.ts +17 -11
  301. package/src/worklet.ts +17 -0
  302. package/src/effects_transform.ts +0 -718
  303. package/src/mastering_repair.ts +0 -273
@@ -1,5 +1,15 @@
1
1
  import { panLawCode, panModeCode } from '../codes';
2
2
  import type { EqBand, PanLawInput, PanMode, RealtimeEngine } from '../index';
3
+ import type { InsertParamOverrideMap } from './engine-mixer-facade';
4
+ import {
5
+ applyFullStripJson,
6
+ clearInsertParamOverrides,
7
+ emptyStripJson,
8
+ hasInsertParamOverrides,
9
+ type InsertParamOverride,
10
+ insertParamOverrideKey,
11
+ type StripJsonTarget,
12
+ } from './engine-mixer-facade';
3
13
  import type { SonareEngineInstrumentSyncMessage, SonareEngineSyncMessage } from './messages';
4
14
 
5
15
  /**
@@ -14,20 +24,83 @@ export interface EngineStripContext {
14
24
  postInstrumentSync(message: SonareEngineInstrumentSyncMessage): void;
15
25
  ensureTrackLane(target: string | number): number;
16
26
  resolveTargetId(target: string | number): number;
27
+ readStripJson(target: StripJsonTarget): string | undefined;
28
+ writeStripJson(target: StripJsonTarget, sceneJson: string): void;
29
+ readonly insertParamOverrides: InsertParamOverrideMap;
17
30
  }
18
31
 
19
32
  function trackIdFor(ctx: EngineStripContext, target: string | number): number {
20
33
  return ctx.trackLaneIds[ctx.ensureTrackLane(target)];
21
34
  }
22
35
 
36
+ type SceneEntry = Record<string, unknown>;
37
+
38
+ /**
39
+ * Folds a setter's change into the strip's cached scene JSON, so the next
40
+ * syncMixer re-post replays it instead of reverting it on the worklet.
41
+ */
42
+ function mergeStripJson(
43
+ ctx: EngineStripContext,
44
+ target: StripJsonTarget,
45
+ update: (entry: SceneEntry) => void,
46
+ ): void {
47
+ const scene = JSON.parse(ctx.readStripJson(target) ?? emptyStripJson(target)) as {
48
+ strips: SceneEntry[];
49
+ buses: SceneEntry[];
50
+ };
51
+ update(target.kind === 'bus' ? scene.buses[0] : scene.strips[0]);
52
+ ctx.writeStripJson(target, JSON.stringify(scene));
53
+ }
54
+
55
+ function mergeEqBand(
56
+ ctx: EngineStripContext,
57
+ target: StripJsonTarget,
58
+ bandIndex: number,
59
+ bandJson: string,
60
+ ): void {
61
+ mergeStripJson(ctx, target, (entry) => {
62
+ const eq = (entry.eq ?? { enabled: true, bands: [] }) as { bands?: unknown[] };
63
+ const bands = eq.bands ?? [];
64
+ while (bands.length < bandIndex) {
65
+ bands.push({});
66
+ }
67
+ bands[bandIndex] = JSON.parse(bandJson);
68
+ entry.eq = { ...eq, bands };
69
+ });
70
+ }
71
+
72
+ function setInsertParamByName(
73
+ ctx: EngineStripContext,
74
+ target: StripJsonTarget,
75
+ insertIndex: number,
76
+ paramName: string,
77
+ value: number,
78
+ applyNative: () => void,
79
+ message: SonareEngineSyncMessage,
80
+ ): void {
81
+ applyNative();
82
+ // Keep the construction scene unchanged. Rewriting insert params here makes
83
+ // a later syncMixer rebuild stateful effects; the override is replayed after
84
+ // the scene on both engines instead.
85
+ const override: InsertParamOverride = { target, insertIndex, paramName, value };
86
+ ctx.insertParamOverrides.set(insertParamOverrideKey(override), override);
87
+ ctx.postSync(message);
88
+ }
89
+
23
90
  export function setTrackStripJson(
24
91
  ctx: EngineStripContext,
25
92
  trackId: number,
26
93
  sceneJson: string,
27
94
  trackStripJson: Map<number, string>,
28
- ): void {
29
- ctx.offlineEngine.setTrackStripJson(trackId, sceneJson);
95
+ ): { resetInserts: boolean } {
96
+ const target: StripJsonTarget = { kind: 'track', trackId };
97
+ const resetInserts =
98
+ (trackStripJson.has(trackId) && trackStripJson.get(trackId) !== sceneJson) ||
99
+ hasInsertParamOverrides(ctx.insertParamOverrides, target);
100
+ applyFullStripJson(ctx.offlineEngine, target, sceneJson, resetInserts);
101
+ clearInsertParamOverrides(ctx.insertParamOverrides, target);
30
102
  trackStripJson.set(trackId, sceneJson);
103
+ return { resetInserts };
31
104
  }
32
105
 
33
106
  export function setTrackStripEqBand(
@@ -39,6 +112,7 @@ export function setTrackStripEqBand(
39
112
  const trackId = trackIdFor(ctx, target);
40
113
  const bandJson = typeof band === 'string' ? band : JSON.stringify(band);
41
114
  ctx.offlineEngine.setTrackStripEqBandJson(trackId, bandIndex, bandJson);
115
+ mergeEqBand(ctx, { kind: 'track', trackId }, bandIndex, bandJson);
42
116
  ctx.postSync({ type: 'syncTrackStripEqBand', trackId, bandIndex, bandJson });
43
117
  }
44
118
 
@@ -68,8 +142,16 @@ export function setTrackStripInsertParamByName(
68
142
  value: number,
69
143
  ): void {
70
144
  const trackId = trackIdFor(ctx, target);
71
- ctx.offlineEngine.setTrackStripInsertParamByName(trackId, insertIndex, paramName, value);
72
- ctx.postSync({ type: 'syncTrackStripInsertParamByName', trackId, insertIndex, paramName, value });
145
+ setInsertParamByName(
146
+ ctx,
147
+ { kind: 'track', trackId },
148
+ insertIndex,
149
+ paramName,
150
+ value,
151
+ () =>
152
+ ctx.offlineEngine.restoreTrackStripInsertParamByName(trackId, insertIndex, paramName, value),
153
+ { type: 'syncTrackStripInsertParamByName', trackId, insertIndex, paramName, value },
154
+ );
73
155
  }
74
156
 
75
157
  export function setTrackStripPan(
@@ -79,6 +161,9 @@ export function setTrackStripPan(
79
161
  ): void {
80
162
  const trackId = trackIdFor(ctx, target);
81
163
  ctx.offlineEngine.setTrackStripPan(trackId, pan);
164
+ mergeStripJson(ctx, { kind: 'track', trackId }, (entry) => {
165
+ entry.pan = pan;
166
+ });
82
167
  ctx.postSync({ type: 'syncTrackStripPan', trackId, pan });
83
168
  }
84
169
 
@@ -90,6 +175,9 @@ export function setTrackStripPanLaw(
90
175
  const trackId = trackIdFor(ctx, target);
91
176
  const code = panLawCode(panLaw);
92
177
  ctx.offlineEngine.setTrackStripPanLaw(trackId, code);
178
+ mergeStripJson(ctx, { kind: 'track', trackId }, (entry) => {
179
+ entry.panLaw = code;
180
+ });
93
181
  ctx.postSync({ type: 'syncTrackStripPanLaw', trackId, panLaw: code });
94
182
  }
95
183
 
@@ -101,6 +189,9 @@ export function setTrackStripPanMode(
101
189
  const trackId = trackIdFor(ctx, target);
102
190
  const code = panModeCode(panMode);
103
191
  ctx.offlineEngine.setTrackStripPanMode(trackId, code);
192
+ mergeStripJson(ctx, { kind: 'track', trackId }, (entry) => {
193
+ entry.panMode = code;
194
+ });
104
195
  ctx.postSync({ type: 'syncTrackStripPanMode', trackId, panMode: code });
105
196
  }
106
197
 
@@ -112,6 +203,10 @@ export function setTrackStripDualPan(
112
203
  ): void {
113
204
  const trackId = trackIdFor(ctx, target);
114
205
  ctx.offlineEngine.setTrackStripDualPan(trackId, leftPan, rightPan);
206
+ mergeStripJson(ctx, { kind: 'track', trackId }, (entry) => {
207
+ entry.dualPanLeft = leftPan;
208
+ entry.dualPanRight = rightPan;
209
+ });
115
210
  ctx.postSync({ type: 'syncTrackStripDualPan', trackId, leftPan, rightPan });
116
211
  }
117
212
 
@@ -122,9 +217,26 @@ export function setTrackStripChannelDelaySamples(
122
217
  ): void {
123
218
  const trackId = trackIdFor(ctx, target);
124
219
  ctx.offlineEngine.setTrackStripChannelDelaySamples(trackId, delaySamples);
220
+ mergeStripJson(ctx, { kind: 'track', trackId }, (entry) => {
221
+ entry.channelDelaySamples = delaySamples;
222
+ });
125
223
  ctx.postSync({ type: 'syncTrackStripChannelDelaySamples', trackId, delaySamples });
126
224
  }
127
225
 
226
+ /**
227
+ * Records a master fader or pan value the parameter path applied, so a master
228
+ * strip re-post does not reset it; a track lane keeps these outside its strip.
229
+ */
230
+ export function cacheMasterStripScalar(
231
+ ctx: EngineStripContext,
232
+ field: 'faderDb' | 'pan',
233
+ value: number,
234
+ ): void {
235
+ mergeStripJson(ctx, { kind: 'master' }, (entry) => {
236
+ entry[field] = value;
237
+ });
238
+ }
239
+
128
240
  export function setMasterStripEqBand(
129
241
  ctx: EngineStripContext,
130
242
  bandIndex: number,
@@ -132,6 +244,7 @@ export function setMasterStripEqBand(
132
244
  ): void {
133
245
  const bandJson = typeof band === 'string' ? band : JSON.stringify(band);
134
246
  ctx.offlineEngine.setMasterStripEqBandJson(bandIndex, bandJson);
247
+ mergeEqBand(ctx, { kind: 'master' }, bandIndex, bandJson);
135
248
  ctx.postSync({ type: 'syncMasterStripEqBand', bandIndex, bandJson });
136
249
  }
137
250
 
@@ -151,8 +264,15 @@ export function setMasterStripInsertParamByName(
151
264
  paramName: string,
152
265
  value: number,
153
266
  ): void {
154
- ctx.offlineEngine.setMasterStripInsertParamByName(insertIndex, paramName, value);
155
- ctx.postSync({ type: 'syncMasterStripInsertParamByName', insertIndex, paramName, value });
267
+ setInsertParamByName(
268
+ ctx,
269
+ { kind: 'master' },
270
+ insertIndex,
271
+ paramName,
272
+ value,
273
+ () => ctx.offlineEngine.restoreMasterStripInsertParamByName(insertIndex, paramName, value),
274
+ { type: 'syncMasterStripInsertParamByName', insertIndex, paramName, value },
275
+ );
156
276
  }
157
277
 
158
278
  export function setBusStripInsertParamByName(
@@ -162,8 +282,86 @@ export function setBusStripInsertParamByName(
162
282
  paramName: string,
163
283
  value: number,
164
284
  ): void {
165
- ctx.offlineEngine.setBusStripInsertParamByName(busId, insertIndex, paramName, value);
166
- ctx.postSync({ type: 'syncBusStripInsertParamByName', busId, insertIndex, paramName, value });
285
+ setInsertParamByName(
286
+ ctx,
287
+ { kind: 'bus', busId },
288
+ insertIndex,
289
+ paramName,
290
+ value,
291
+ () => ctx.offlineEngine.restoreBusStripInsertParamByName(busId, insertIndex, paramName, value),
292
+ { type: 'syncBusStripInsertParamByName', busId, insertIndex, paramName, value },
293
+ );
294
+ }
295
+
296
+ export function setBusStripInsertBypassed(
297
+ ctx: EngineStripContext,
298
+ busId: number,
299
+ insertIndex: number,
300
+ bypassed: boolean,
301
+ resetOnBypass: boolean,
302
+ ): void {
303
+ ctx.offlineEngine.setBusStripInsertBypassed(busId, insertIndex, bypassed, resetOnBypass);
304
+ ctx.postSync({ type: 'syncBusStripInsertBypassed', busId, insertIndex, bypassed, resetOnBypass });
305
+ }
306
+
307
+ export function setBusStripEqBand(
308
+ ctx: EngineStripContext,
309
+ busId: number,
310
+ bandIndex: number,
311
+ band: EqBand | string,
312
+ ): void {
313
+ const bandJson = typeof band === 'string' ? band : JSON.stringify(band);
314
+ ctx.offlineEngine.setBusStripEqBandJson(busId, bandIndex, bandJson);
315
+ mergeEqBand(ctx, { kind: 'bus', busId }, bandIndex, bandJson);
316
+ ctx.postSync({ type: 'syncBusStripEqBand', busId, bandIndex, bandJson });
317
+ }
318
+
319
+ export function setBusStripPan(ctx: EngineStripContext, busId: number, pan: number): void {
320
+ ctx.offlineEngine.setBusStripPan(busId, pan);
321
+ mergeStripJson(ctx, { kind: 'bus', busId }, (entry) => {
322
+ entry.pan = pan;
323
+ });
324
+ ctx.postSync({ type: 'syncBusStripPan', busId, pan });
325
+ }
326
+
327
+ export function setBusStripPanLaw(
328
+ ctx: EngineStripContext,
329
+ busId: number,
330
+ panLaw: PanLawInput,
331
+ ): void {
332
+ const code = panLawCode(panLaw);
333
+ ctx.offlineEngine.setBusStripPanLaw(busId, code);
334
+ mergeStripJson(ctx, { kind: 'bus', busId }, (entry) => {
335
+ entry.panLaw = code;
336
+ });
337
+ ctx.postSync({ type: 'syncBusStripPanLaw', busId, panLaw: code });
338
+ }
339
+
340
+ export function setBusStripPanMode(
341
+ ctx: EngineStripContext,
342
+ busId: number,
343
+ panMode: PanMode | number,
344
+ ): void {
345
+ const code = panModeCode(panMode);
346
+ ctx.offlineEngine.setBusStripPanMode(busId, code);
347
+ mergeStripJson(ctx, { kind: 'bus', busId }, (entry) => {
348
+ entry.panMode = code;
349
+ });
350
+ ctx.postSync({ type: 'syncBusStripPanMode', busId, panMode: code });
351
+ }
352
+
353
+ export function setBusStripDualPan(
354
+ ctx: EngineStripContext,
355
+ busId: number,
356
+ leftPan: number,
357
+ rightPan: number,
358
+ ): void {
359
+ ctx.offlineEngine.setBusStripDualPan(busId, leftPan, rightPan);
360
+ mergeStripJson(ctx, { kind: 'bus', busId }, (entry) => {
361
+ entry.dualPanLeft = leftPan;
362
+ entry.dualPanRight = rightPan;
363
+ });
364
+ ctx.postSync({ type: 'syncBusStripDualPan', busId, leftPan, rightPan });
167
365
  }
168
366
 
169
367
  export function pushMidiNoteOn(
@@ -232,6 +430,77 @@ export function pushMidiCc(
232
430
  });
233
431
  }
234
432
 
433
+ export function pushMidiPitchBend(
434
+ ctx: EngineStripContext,
435
+ trackId: string | number,
436
+ group: number,
437
+ channel: number,
438
+ bend14: number,
439
+ renderFrame: number,
440
+ ): void {
441
+ const destinationId = ctx.resolveTargetId(trackId);
442
+ ctx.offlineEngine.pushMidiPitchBend(destinationId, group, channel, bend14, renderFrame);
443
+ ctx.postSync({
444
+ type: 'syncMidiPitchBend',
445
+ destinationId,
446
+ group,
447
+ channel,
448
+ data0: bend14,
449
+ data1: 0,
450
+ renderFrame,
451
+ });
452
+ }
453
+
454
+ export function pushMidiChannelPressure(
455
+ ctx: EngineStripContext,
456
+ trackId: string | number,
457
+ group: number,
458
+ channel: number,
459
+ pressure: number,
460
+ renderFrame: number,
461
+ ): void {
462
+ const destinationId = ctx.resolveTargetId(trackId);
463
+ ctx.offlineEngine.pushMidiChannelPressure(destinationId, group, channel, pressure, renderFrame);
464
+ ctx.postSync({
465
+ type: 'syncMidiChannelPressure',
466
+ destinationId,
467
+ group,
468
+ channel,
469
+ data0: pressure,
470
+ data1: 0,
471
+ renderFrame,
472
+ });
473
+ }
474
+
475
+ export function pushMidiPolyPressure(
476
+ ctx: EngineStripContext,
477
+ trackId: string | number,
478
+ group: number,
479
+ channel: number,
480
+ note: number,
481
+ pressure: number,
482
+ renderFrame: number,
483
+ ): void {
484
+ const destinationId = ctx.resolveTargetId(trackId);
485
+ ctx.offlineEngine.pushMidiPolyPressure(
486
+ destinationId,
487
+ group,
488
+ channel,
489
+ note,
490
+ pressure,
491
+ renderFrame,
492
+ );
493
+ ctx.postSync({
494
+ type: 'syncMidiPolyPressure',
495
+ destinationId,
496
+ group,
497
+ channel,
498
+ data0: note,
499
+ data1: pressure,
500
+ renderFrame,
501
+ });
502
+ }
503
+
235
504
  export function pushMidiUmp(
236
505
  ctx: EngineStripContext,
237
506
  trackId: string | number,
@@ -239,7 +508,7 @@ export function pushMidiUmp(
239
508
  renderFrame: number,
240
509
  ): void {
241
510
  const destinationId = ctx.resolveTargetId(trackId);
242
- ctx.offlineEngine.pushMidiUmp(destinationId, word0, renderFrame);
511
+ ctx.offlineEngine.pushMidiUmp(destinationId, [word0], renderFrame);
243
512
  ctx.postSync({ type: 'syncMidiUmp', destinationId, word0, renderFrame });
244
513
  }
245
514
 
@@ -276,6 +545,8 @@ export function setSf2Instrument(
276
545
  gain?: number;
277
546
  polyphony?: number;
278
547
  preferModelForModeledFamilies?: boolean;
548
+ clearBankRig?: boolean;
549
+ gsEfxRealization?: 'modern' | 'classic';
279
550
  },
280
551
  ): void {
281
552
  const destinationId = ctx.resolveTargetId(trackId);
@@ -54,15 +54,23 @@ export function buildTempoSync(
54
54
  }
55
55
 
56
56
  /**
57
- * Resolves a target id from a string or number; non-numeric strings resolve to
58
- * 0, mirroring the engine's integer-id namespace.
57
+ * Resolves a target id given as a number, or as a string naming one.
58
+ *
59
+ * Both spellings reach one refusal. Reading the string with `Number.parseInt`
60
+ * stops at the first non-digit, so `"3.5"` resolves to `3` and `"5abc"` to `5`,
61
+ * and an unparseable name resolves to `0` -- all ids the caller never named.
62
+ * `0` is a legal destination, so the native check these feed cannot tell the
63
+ * substitution from a deliberate choice and never reports one.
59
64
  */
60
65
  export function resolveTargetId(target: string | number): number {
61
- if (typeof target === 'number') {
62
- return target;
66
+ // An empty or blank string is not a spelling of zero, which is what Number
67
+ // reads it as.
68
+ const value =
69
+ typeof target === 'number' ? target : target.trim() === '' ? Number.NaN : Number(target);
70
+ if (!Number.isInteger(value)) {
71
+ throw new RangeError(`target id must be an integer, got ${JSON.stringify(target)}`);
63
72
  }
64
- const parsed = Number.parseInt(target, 10);
65
- return Number.isFinite(parsed) ? parsed : 0;
73
+ return value;
66
74
  }
67
75
 
68
76
  /** Resolves a registered parameter name or passes through a numeric id. */