@libraz/libsonare 1.6.0 → 1.7.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 (47) hide show
  1. package/README.md +2 -2
  2. package/dist/analysis.d.ts +88 -9
  3. package/dist/analysis.js +152 -42
  4. package/dist/analysis.js.map +1 -1
  5. package/dist/index.d.ts +129 -24
  6. package/dist/index.js +455 -140
  7. package/dist/index.js.map +1 -1
  8. package/dist/schemas/realtime-voice-changer-preset.schema.json +2 -2
  9. package/dist/sonare-analysis.js +1 -1
  10. package/dist/sonare-analysis.wasm +0 -0
  11. package/dist/sonare.js +1 -1
  12. package/dist/sonare.wasm +0 -0
  13. package/dist/worker.js +56 -29
  14. package/dist/worker.js.map +1 -1
  15. package/dist/worklet.d.ts +62 -10
  16. package/dist/worklet.js +193 -42
  17. package/dist/worklet.js.map +1 -1
  18. package/package.json +3 -3
  19. package/src/analysis_helpers.ts +34 -29
  20. package/src/audio.ts +7 -2
  21. package/src/codes.ts +47 -11
  22. package/src/effects_transform.ts +179 -10
  23. package/src/feature_music.ts +8 -1
  24. package/src/feature_spectral.ts +64 -2
  25. package/src/feature_spectrogram.ts +44 -3
  26. package/src/index.ts +21 -3
  27. package/src/mixer.ts +3 -3
  28. package/src/project.ts +6 -0
  29. package/src/project_class.ts +143 -16
  30. package/src/project_internal.ts +14 -5
  31. package/src/project_types.ts +45 -1
  32. package/src/public_types_mixing.ts +16 -0
  33. package/src/public_types_realtime.ts +23 -5
  34. package/src/quick_analysis.ts +21 -3
  35. package/src/realtime_engine.ts +14 -3
  36. package/src/sonare.js.d.ts +64 -0
  37. package/src/stream_analyzer.ts +6 -1
  38. package/src/web_midi.ts +10 -7
  39. package/src/worklet/engine-node.ts +54 -19
  40. package/src/worklet/engine-parameter-facade.ts +30 -1
  41. package/src/worklet/engine-processor.ts +52 -20
  42. package/src/worklet/engine-register.ts +1 -1
  43. package/src/worklet/engine-strips.ts +2 -2
  44. package/src/worklet/engine.ts +10 -0
  45. package/src/worklet/guards.ts +99 -7
  46. package/src/worklet/messages.ts +41 -1
  47. package/src/worklet/protocol.ts +4 -0
@@ -1,6 +1,7 @@
1
+ import type { EngineCaptureStatus } from '../index';
1
2
  import type {
2
3
  SonareEngineCaptureRequestMessage,
3
- SonareEngineCaptureResponseMessage,
4
+ SonareEngineCaptureResponseMessageInternal,
4
5
  SonareEngineClipPageRequestMessage,
5
6
  SonareEngineSyncMessage,
6
7
  SonareEngineTransportRequestMessage,
@@ -91,17 +92,108 @@ export function isEngineCaptureRequestMessage(
91
92
  );
92
93
  }
93
94
 
94
- export function isEngineCaptureResponseMessage(
95
- value: unknown,
96
- ): value is SonareEngineCaptureResponseMessage {
95
+ function isCaptureStatus(value: unknown): value is EngineCaptureStatus {
97
96
  return (
98
97
  isRecord(value) &&
99
- value.type === 'captureResponse' &&
100
- typeof value.requestId === 'number' &&
101
- typeof value.ok === 'boolean'
98
+ typeof value.capturedFrames === 'number' &&
99
+ Number.isSafeInteger(value.capturedFrames) &&
100
+ value.capturedFrames >= 0 &&
101
+ typeof value.overflowCount === 'number' &&
102
+ Number.isSafeInteger(value.overflowCount) &&
103
+ value.overflowCount >= 0 &&
104
+ typeof value.armed === 'boolean' &&
105
+ typeof value.punchEnabled === 'boolean' &&
106
+ (value.source === 'input' || value.source === 'output') &&
107
+ typeof value.recordOffsetSamples === 'number' &&
108
+ Number.isSafeInteger(value.recordOffsetSamples)
109
+ );
110
+ }
111
+
112
+ function isCaptureChannel(value: unknown): value is Float32Array {
113
+ // Capture responses are transferred out of the worklet. A typed view onto
114
+ // the WASM heap or a SharedArrayBuffer must not cross that boundary: the
115
+ // former can be detached by memory growth and the latter cannot be listed
116
+ // in a transfer list. `instanceof` also rejects boxed number arrays.
117
+ return (
118
+ value instanceof Float32Array &&
119
+ typeof ArrayBuffer !== 'undefined' &&
120
+ value.buffer instanceof ArrayBuffer
102
121
  );
103
122
  }
104
123
 
124
+ function isCaptureChannels(value: unknown): value is Float32Array[] {
125
+ return Array.isArray(value) && value.every((channel) => isCaptureChannel(channel));
126
+ }
127
+
128
+ function hasOwn(value: Record<string, unknown>, key: string): boolean {
129
+ // biome-ignore lint/suspicious/noPrototypeBuiltins: Object.hasOwn is newer than the ES2020 target.
130
+ return Object.prototype.hasOwnProperty.call(value, key);
131
+ }
132
+
133
+ /** Return a request ID even when the response payload itself is malformed. */
134
+ export function engineCaptureResponseRequestId(value: unknown): number | undefined {
135
+ if (
136
+ !isRecord(value) ||
137
+ value.type !== 'captureResponse' ||
138
+ typeof value.requestId !== 'number' ||
139
+ !Number.isSafeInteger(value.requestId)
140
+ ) {
141
+ return undefined;
142
+ }
143
+ return value.requestId;
144
+ }
145
+
146
+ export function isEngineCaptureResponseMessage(
147
+ value: unknown,
148
+ ): value is SonareEngineCaptureResponseMessageInternal {
149
+ const requestId = engineCaptureResponseRequestId(value);
150
+ if (requestId === undefined || !isRecord(value)) {
151
+ return false;
152
+ }
153
+ if (value.ok === false) {
154
+ return (
155
+ typeof value.error === 'string' && !hasOwn(value, 'status') && !hasOwn(value, 'channels')
156
+ );
157
+ }
158
+ if (value.ok !== true || hasOwn(value, 'error')) {
159
+ return false;
160
+ }
161
+ const hasStatus = hasOwn(value, 'status');
162
+ const hasChannels = hasOwn(value, 'channels');
163
+ if (hasStatus && hasChannels) {
164
+ return false;
165
+ }
166
+ if (hasStatus) {
167
+ return isCaptureStatus(value.status);
168
+ }
169
+ if (hasChannels) {
170
+ return isCaptureChannels(value.channels);
171
+ }
172
+ return true;
173
+ }
174
+
175
+ /**
176
+ * Check that a strict success response belongs to the requested operation.
177
+ * Failure responses are operation-independent and are therefore valid for
178
+ * every pending request (the node rejects them after this check).
179
+ */
180
+ export function isEngineCaptureResponseForOperation(
181
+ response: SonareEngineCaptureResponseMessageInternal,
182
+ op: SonareEngineCaptureRequestMessage['op'],
183
+ ): boolean {
184
+ if (!response.ok) {
185
+ return true;
186
+ }
187
+ switch (op) {
188
+ case 'status':
189
+ return 'status' in response;
190
+ case 'read':
191
+ return 'channels' in response;
192
+ case 'reset':
193
+ return !('status' in response) && !('channels' in response);
194
+ }
195
+ }
196
+
105
197
  export function isEngineTransportRequestMessage(
106
198
  value: unknown,
107
199
  ): value is SonareEngineTransportRequestMessage {
@@ -196,7 +196,7 @@ export interface WorkletTransport {
196
196
  postMessage?: (
197
197
  message:
198
198
  | SonareWorkletTransportMessage
199
- | SonareEngineCaptureResponseMessage
199
+ | SonareEngineCaptureResponseMessageInternal
200
200
  | SonareEngineTransportResponseMessage
201
201
  | SonareEngineSyncErrorMessage,
202
202
  transfer?: Transferable[],
@@ -636,6 +636,12 @@ export interface SonareEngineCaptureRequestMessage {
636
636
  op: 'status' | 'read' | 'reset';
637
637
  }
638
638
 
639
+ /**
640
+ * Public capture response shape retained for source compatibility.
641
+ *
642
+ * The worklet wire protocol is stricter than this legacy structural type; use
643
+ * `SonareEngineCaptureResponseMessageInternal` inside the implementation.
644
+ */
639
645
  export interface SonareEngineCaptureResponseMessage {
640
646
  type: 'captureResponse';
641
647
  requestId: number;
@@ -645,6 +651,40 @@ export interface SonareEngineCaptureResponseMessage {
645
651
  error?: string;
646
652
  }
647
653
 
654
+ interface SonareEngineCaptureStatusResponseMessageInternal {
655
+ type: 'captureResponse';
656
+ requestId: number;
657
+ ok: true;
658
+ status: EngineCaptureStatus;
659
+ }
660
+
661
+ interface SonareEngineCaptureReadResponseMessageInternal {
662
+ type: 'captureResponse';
663
+ requestId: number;
664
+ ok: true;
665
+ channels: Float32Array[];
666
+ }
667
+
668
+ interface SonareEngineCaptureResetResponseMessageInternal {
669
+ type: 'captureResponse';
670
+ requestId: number;
671
+ ok: true;
672
+ }
673
+
674
+ interface SonareEngineCaptureErrorResponseMessageInternal {
675
+ type: 'captureResponse';
676
+ requestId: number;
677
+ ok: false;
678
+ error: string;
679
+ }
680
+
681
+ /** Strict wire response type used only by the worklet implementation. */
682
+ export type SonareEngineCaptureResponseMessageInternal =
683
+ | SonareEngineCaptureStatusResponseMessageInternal
684
+ | SonareEngineCaptureReadResponseMessageInternal
685
+ | SonareEngineCaptureResetResponseMessageInternal
686
+ | SonareEngineCaptureErrorResponseMessageInternal;
687
+
648
688
  export interface SonareEngineTransportRequestMessage {
649
689
  type: 'transportRequest';
650
690
  requestId: number;
@@ -108,6 +108,9 @@ export enum SonareEngineCommandType {
108
108
  SetMetronome = 15,
109
109
  SetMarker = 16,
110
110
  SeekMarker = 17,
111
+ // Queueable lane monitor-mode transition. The worklet command vocabulary
112
+ // deliberately leaves 18..25 unused; this is the stable ABI-v3 ordinal.
113
+ SetTrackMonitorMode = 26,
111
114
  }
112
115
 
113
116
  export enum SonareEngineTelemetryType {
@@ -136,6 +139,7 @@ export enum SonareEngineTelemetryError {
136
139
  MidiClockOverflow = 17,
137
140
  MetronomeOverflow = 18,
138
141
  InvalidCommand = 19,
142
+ MaxChannelsExceeded = 20,
139
143
  }
140
144
 
141
145
  export interface SonareMeterRingBuffer {