@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.
- package/NOTICE +178 -0
- package/README.md +26 -203
- package/dist/_chain_config.d.ts +14 -0
- package/dist/_chain_config.d.ts.map +1 -0
- package/dist/_effects_common.d.ts +6 -0
- package/dist/_effects_common.d.ts.map +1 -0
- package/dist/_feature_validation.d.ts +8 -0
- package/dist/_feature_validation.d.ts.map +1 -0
- package/dist/_fft_options.d.ts +24 -0
- package/dist/_fft_options.d.ts.map +1 -0
- package/dist/align_take.d.ts +50 -0
- package/dist/align_take.d.ts.map +1 -0
- package/dist/analysis.d.ts +29 -5840
- package/dist/analysis.d.ts.map +1 -0
- package/dist/analysis.js +873 -722
- package/dist/analysis.js.map +1 -1
- package/dist/analysis_helpers.d.ts +9 -0
- package/dist/analysis_helpers.d.ts.map +1 -0
- package/dist/audio.d.ts +163 -0
- package/dist/audio.d.ts.map +1 -0
- package/dist/clip_page_streamer.d.ts +133 -0
- package/dist/clip_page_streamer.d.ts.map +1 -0
- package/dist/codes.d.ts +44 -0
- package/dist/codes.d.ts.map +1 -0
- package/dist/effects_mastering.d.ts +23 -0
- package/dist/effects_mastering.d.ts.map +1 -0
- package/dist/effects_note_ops.d.ts +477 -0
- package/dist/effects_note_ops.d.ts.map +1 -0
- package/dist/effects_percussive.d.ts +185 -0
- package/dist/effects_percussive.d.ts.map +1 -0
- package/dist/effects_separation.d.ts +65 -0
- package/dist/effects_separation.d.ts.map +1 -0
- package/dist/effects_spectral.d.ts +28 -0
- package/dist/effects_spectral.d.ts.map +1 -0
- package/dist/effects_timepitch.d.ts +129 -0
- package/dist/effects_timepitch.d.ts.map +1 -0
- package/dist/effects_voice_change.d.ts +53 -0
- package/dist/effects_voice_change.d.ts.map +1 -0
- package/dist/errors.d.ts +51 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/feature_core.d.ts +341 -0
- package/dist/feature_core.d.ts.map +1 -0
- package/dist/feature_decompose.d.ts +278 -0
- package/dist/feature_decompose.d.ts.map +1 -0
- package/dist/feature_inverse.d.ts +128 -0
- package/dist/feature_inverse.d.ts.map +1 -0
- package/dist/feature_loudness.d.ts +66 -0
- package/dist/feature_loudness.d.ts.map +1 -0
- package/dist/feature_music.d.ts +307 -0
- package/dist/feature_music.d.ts.map +1 -0
- package/dist/feature_pitch.d.ts +108 -0
- package/dist/feature_pitch.d.ts.map +1 -0
- package/dist/feature_resample.d.ts +16 -0
- package/dist/feature_resample.d.ts.map +1 -0
- package/dist/feature_spectral.d.ts +137 -0
- package/dist/feature_spectral.d.ts.map +1 -0
- package/dist/feature_spectrogram.d.ts +198 -0
- package/dist/feature_spectrogram.d.ts.map +1 -0
- package/dist/features.d.ts +10 -0
- package/dist/features.d.ts.map +1 -0
- package/dist/hrtf/default.shrf +0 -0
- package/dist/index.d.ts +74 -7431
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3758 -1362
- package/dist/index.js.map +1 -1
- package/dist/instrument_types.d.ts +517 -0
- package/dist/instrument_types.d.ts.map +1 -0
- package/dist/live_audio.d.ts +35 -0
- package/dist/live_audio.d.ts.map +1 -0
- package/dist/mastering_chain.d.ts +213 -0
- package/dist/mastering_chain.d.ts.map +1 -0
- package/dist/mastering_core.d.ts +457 -0
- package/dist/mastering_core.d.ts.map +1 -0
- package/dist/mastering_dynamics.d.ts +80 -0
- package/dist/mastering_dynamics.d.ts.map +1 -0
- package/dist/metering.d.ts +287 -0
- package/dist/metering.d.ts.map +1 -0
- package/dist/mixer.d.ts +464 -0
- package/dist/mixer.d.ts.map +1 -0
- package/dist/mixing_assistant.d.ts +62 -0
- package/dist/mixing_assistant.d.ts.map +1 -0
- package/dist/mixing_oneshot.d.ts +40 -0
- package/dist/mixing_oneshot.d.ts.map +1 -0
- package/dist/module_state.d.ts +15 -0
- package/dist/module_state.d.ts.map +1 -0
- package/dist/opfs_clip_pages.d.ts +28 -0
- package/dist/opfs_clip_pages.d.ts.map +1 -0
- package/dist/playback_renderer.d.ts +128 -0
- package/dist/playback_renderer.d.ts.map +1 -0
- package/dist/polyphony.d.ts +202 -0
- package/dist/polyphony.d.ts.map +1 -0
- package/dist/project.d.ts +8 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project_class.d.ts +562 -0
- package/dist/project_class.d.ts.map +1 -0
- package/dist/project_internal.d.ts +194 -0
- package/dist/project_internal.d.ts.map +1 -0
- package/dist/project_synth.d.ts +74 -0
- package/dist/project_synth.d.ts.map +1 -0
- package/dist/project_types.d.ts +652 -0
- package/dist/project_types.d.ts.map +1 -0
- package/dist/public_types.d.ts +185 -0
- package/dist/public_types.d.ts.map +1 -0
- package/dist/public_types_acoustic.d.ts +215 -0
- package/dist/public_types_acoustic.d.ts.map +1 -0
- package/dist/public_types_mastering.d.ts +510 -0
- package/dist/public_types_mastering.d.ts.map +1 -0
- package/dist/public_types_mixing.d.ts +436 -0
- package/dist/public_types_mixing.d.ts.map +1 -0
- package/dist/public_types_music.d.ts +619 -0
- package/dist/public_types_music.d.ts.map +1 -0
- package/dist/public_types_playback.d.ts +164 -0
- package/dist/public_types_playback.d.ts.map +1 -0
- package/dist/public_types_realtime.d.ts +174 -0
- package/dist/public_types_realtime.d.ts.map +1 -0
- package/dist/public_types_repair.d.ts +424 -0
- package/dist/public_types_repair.d.ts.map +1 -0
- package/dist/public_types_spectral.d.ts +697 -0
- package/dist/public_types_spectral.d.ts.map +1 -0
- package/dist/quick_analysis.d.ts +445 -0
- package/dist/quick_analysis.d.ts.map +1 -0
- package/dist/realtime_engine.d.ts +850 -0
- package/dist/realtime_engine.d.ts.map +1 -0
- package/dist/realtime_voice_changer.d.ts +158 -0
- package/dist/realtime_voice_changer.d.ts.map +1 -0
- package/dist/repair_dereverb.d.ts +187 -0
- package/dist/repair_dereverb.d.ts.map +1 -0
- package/dist/repair_impulsive.d.ts +186 -0
- package/dist/repair_impulsive.d.ts.map +1 -0
- package/dist/repair_noise.d.ts +239 -0
- package/dist/repair_noise.d.ts.map +1 -0
- package/dist/repair_trim.d.ts +123 -0
- package/dist/repair_trim.d.ts.map +1 -0
- package/dist/sample_bank.d.ts +84 -0
- package/dist/sample_bank.d.ts.map +1 -0
- package/dist/scale.d.ts +10 -0
- package/dist/scale.d.ts.map +1 -0
- package/dist/schemas/mixer-scene.schema.json +393 -0
- package/dist/schemas/playback-renderer-config.schema.json +392 -0
- package/dist/sonare-analysis.d.ts +8 -0
- package/dist/sonare-analysis.js +2 -2
- package/dist/sonare-analysis.wasm +0 -0
- package/dist/sonare.d.ts +3909 -0
- package/dist/sonare.js +2 -2
- package/dist/sonare.wasm +0 -0
- package/dist/stream_analyzer.d.ts +163 -0
- package/dist/stream_analyzer.d.ts.map +1 -0
- package/dist/stream_types.d.ts +214 -0
- package/dist/stream_types.d.ts.map +1 -0
- package/dist/streaming_mixing.d.ts +6 -0
- package/dist/streaming_mixing.d.ts.map +1 -0
- package/dist/streaming_processors.d.ts +335 -0
- package/dist/streaming_processors.d.ts.map +1 -0
- package/dist/transcribe.d.ts +77 -0
- package/dist/transcribe.d.ts.map +1 -0
- package/dist/validation.d.ts +140 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/web_midi.d.ts +77 -0
- package/dist/web_midi.d.ts.map +1 -0
- package/dist/worker.d.ts +5 -48
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +94 -41
- package/dist/worker.js.map +1 -1
- package/dist/worker_client.d.ts +96 -0
- package/dist/worker_client.d.ts.map +1 -0
- package/dist/worker_protocol.d.ts +43 -0
- package/dist/worker_protocol.d.ts.map +1 -0
- package/dist/worklet/audio_types.d.ts +21 -0
- package/dist/worklet/audio_types.d.ts.map +1 -0
- package/dist/worklet/engine-automation.d.ts +29 -0
- package/dist/worklet/engine-automation.d.ts.map +1 -0
- package/dist/worklet/engine-capture-facade.d.ts +35 -0
- package/dist/worklet/engine-capture-facade.d.ts.map +1 -0
- package/dist/worklet/engine-clips.d.ts +23 -0
- package/dist/worklet/engine-clips.d.ts.map +1 -0
- package/dist/worklet/engine-markers.d.ts +40 -0
- package/dist/worklet/engine-markers.d.ts.map +1 -0
- package/dist/worklet/engine-mixer-facade.d.ts +128 -0
- package/dist/worklet/engine-mixer-facade.d.ts.map +1 -0
- package/dist/worklet/engine-node.d.ts +81 -0
- package/dist/worklet/engine-node.d.ts.map +1 -0
- package/dist/worklet/engine-offline.d.ts +81 -0
- package/dist/worklet/engine-offline.d.ts.map +1 -0
- package/dist/worklet/engine-options.d.ts +12 -0
- package/dist/worklet/engine-options.d.ts.map +1 -0
- package/dist/worklet/engine-parameter-facade.d.ts +106 -0
- package/dist/worklet/engine-parameter-facade.d.ts.map +1 -0
- package/dist/worklet/engine-processor.d.ts +68 -0
- package/dist/worklet/engine-processor.d.ts.map +1 -0
- package/dist/worklet/engine-register.d.ts +2 -0
- package/dist/worklet/engine-register.d.ts.map +1 -0
- package/dist/worklet/engine-strips.d.ts +73 -0
- package/dist/worklet/engine-strips.d.ts.map +1 -0
- package/dist/worklet/engine-sync.d.ts +37 -0
- package/dist/worklet/engine-sync.d.ts.map +1 -0
- package/dist/worklet/engine-tempo-facade.d.ts +48 -0
- package/dist/worklet/engine-tempo-facade.d.ts.map +1 -0
- package/dist/worklet/engine.d.ts +397 -0
- package/dist/worklet/engine.d.ts.map +1 -0
- package/dist/worklet/guards.d.ts +47 -0
- package/dist/worklet/guards.d.ts.map +1 -0
- package/dist/worklet/messages.d.ts +710 -0
- package/dist/worklet/messages.d.ts.map +1 -0
- package/dist/worklet/mixer-processor.d.ts +46 -0
- package/dist/worklet/mixer-processor.d.ts.map +1 -0
- package/dist/worklet/playback-processor.d.ts +62 -0
- package/dist/worklet/playback-processor.d.ts.map +1 -0
- package/dist/worklet/protocol.d.ts +323 -0
- package/dist/worklet/protocol.d.ts.map +1 -0
- package/dist/worklet/voice-changer-processor.d.ts +41 -0
- package/dist/worklet/voice-changer-processor.d.ts.map +1 -0
- package/dist/worklet.d.ts +16 -2515
- package/dist/worklet.d.ts.map +1 -0
- package/dist/worklet.js +2763 -501
- package/dist/worklet.js.map +1 -1
- package/package.json +23 -12
- package/src/_effects_common.ts +17 -0
- package/src/_feature_validation.ts +34 -0
- package/src/_fft_options.ts +39 -0
- package/src/align_take.ts +64 -0
- package/src/analysis.ts +56 -3
- package/src/analysis_helpers.ts +7 -0
- package/src/audio.ts +106 -3
- package/src/codes.ts +39 -2
- package/src/effects_mastering.ts +97 -22
- package/src/effects_note_ops.ts +635 -0
- package/src/effects_percussive.ts +217 -0
- package/src/effects_separation.ts +150 -0
- package/src/effects_spectral.ts +60 -0
- package/src/effects_timepitch.ts +377 -0
- package/src/errors.ts +23 -1
- package/src/feature_core.ts +127 -2
- package/src/feature_decompose.ts +633 -0
- package/src/feature_inverse.ts +454 -0
- package/src/feature_loudness.ts +125 -0
- package/src/feature_music.ts +107 -14
- package/src/feature_pitch.ts +96 -1
- package/src/feature_spectral.ts +16 -611
- package/src/feature_spectrogram.ts +63 -450
- package/src/features.ts +36 -22
- package/src/index.ts +282 -30
- package/src/instrument_types.ts +645 -0
- package/src/live_audio.ts +27 -1
- package/src/mastering_chain.ts +184 -0
- package/src/mastering_core.ts +346 -32
- package/src/mastering_dynamics.ts +22 -11
- package/src/metering.ts +67 -24
- package/src/mixer.ts +212 -3
- package/src/mixing_assistant.ts +138 -0
- package/src/mixing_oneshot.ts +10 -5
- package/src/module_state.ts +24 -2
- package/src/playback_renderer.ts +252 -0
- package/src/polyphony.ts +279 -0
- package/src/project.ts +61 -24
- package/src/project_class.ts +450 -27
- package/src/project_internal.ts +149 -42
- package/src/project_synth.ts +67 -1
- package/src/project_types.ts +268 -270
- package/src/public_types.ts +122 -3
- package/src/public_types_acoustic.ts +112 -3
- package/src/public_types_mastering.ts +254 -73
- package/src/public_types_mixing.ts +363 -1
- package/src/public_types_music.ts +312 -2
- package/src/public_types_playback.ts +195 -0
- package/src/public_types_realtime.ts +39 -7
- package/src/public_types_repair.ts +446 -0
- package/src/public_types_spectral.ts +487 -1
- package/src/quick_analysis.ts +203 -26
- package/src/realtime_engine.ts +711 -28
- package/src/realtime_voice_changer.ts +55 -1
- package/src/repair_dereverb.ts +299 -0
- package/src/repair_impulsive.ts +395 -0
- package/src/repair_noise.ts +425 -0
- package/src/repair_trim.ts +226 -0
- package/src/sample_bank.ts +113 -0
- package/src/sonare.js.d.ts +1122 -30
- package/src/stream_analyzer.ts +36 -4
- package/src/stream_types.ts +37 -0
- package/src/streaming_mixing.ts +1 -1
- package/src/streaming_processors.ts +194 -10
- package/src/transcribe.ts +89 -0
- package/src/validation.ts +285 -11
- package/src/web_midi.ts +1 -6
- package/src/worker.ts +18 -2
- package/src/worklet/audio_types.ts +37 -0
- package/src/worklet/engine-mixer-facade.ts +444 -10
- package/src/worklet/engine-node.ts +78 -26
- package/src/worklet/engine-offline.ts +14 -8
- package/src/worklet/engine-parameter-facade.ts +21 -0
- package/src/worklet/engine-processor.ts +272 -83
- package/src/worklet/engine-register.ts +32 -18
- package/src/worklet/engine-strips.ts +280 -9
- package/src/worklet/engine-sync.ts +14 -6
- package/src/worklet/engine.ts +365 -31
- package/src/worklet/guards.ts +140 -44
- package/src/worklet/messages.ts +227 -2
- package/src/worklet/mixer-processor.ts +109 -47
- package/src/worklet/playback-processor.ts +300 -0
- package/src/worklet/protocol.ts +53 -3
- package/src/worklet/voice-changer-processor.ts +17 -11
- package/src/worklet.ts +17 -0
- package/src/effects_transform.ts +0 -718
- package/src/mastering_repair.ts +0 -273
package/dist/worker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/module_state.ts","../src/validation.ts","../src/_chain_config.ts","../src/mastering_chain.ts","../src/codes.ts","../src/public_types_music.ts","../src/analysis_helpers.ts","../src/quick_analysis.ts","../src/index.ts","../src/worker.ts"],"sourcesContent":["/**\n * Numeric error codes carried by a {@link SonareError}. Mirrors the C ABI\n * `SonareError` enum (and the Node / Python surfaces), so the same failure\n * reports the same numeric code on every binding.\n */\nexport enum ErrorCode {\n Ok = 0,\n FileNotFound = 1,\n InvalidFormat = 2,\n DecodeFailed = 3,\n InvalidParameter = 4,\n OutOfMemory = 5,\n NotSupported = 6,\n InvalidState = 7,\n Cancelled = 8,\n Unknown = 99,\n}\n\n/**\n * Error thrown by libsonare on a native (C++) failure. Carries a numeric\n * {@link ErrorCode} `code` plus its canonical `codeName`, so callers can branch\n * on the cause instead of matching message text.\n */\nexport class SonareError extends Error {\n /** Numeric error code, equal to an {@link ErrorCode} value. */\n readonly code: number;\n /** Canonical name of `code`, e.g. `'InvalidParameter'`. */\n readonly codeName: string;\n\n constructor(code: number, codeName: string, message: string) {\n super(message);\n this.name = 'SonareError';\n this.code = code;\n this.codeName = codeName;\n }\n}\n\n/** Type guard: whether a caught value is a libsonare {@link SonareError}. */\nexport function isSonareError(value: unknown): value is SonareError {\n return (\n value instanceof Error &&\n (value as { name?: unknown }).name === 'SonareError' &&\n typeof (value as { code?: unknown }).code === 'number'\n );\n}\n","import { ErrorCode, SonareError } from './errors';\nimport type { SonareModule } from './sonare.js';\n\nlet wrappedModule: SonareModule | null = null;\n\n/**\n * Shape of the structured info the native `sonareExceptionInfo(ptr)` returns.\n */\ninterface NativeExceptionInfo {\n code: number;\n codeName: string;\n message: string;\n}\n\n/**\n * Recover the native exception-object pointer from a value thrown across the\n * WASM boundary. emscripten surfaces a C++ throw in two shapes depending on the\n * toolchain/exception mode:\n * - a raw pointer number (older / classic surfacing), or\n * - a `CppException` object exposing the pointer as `excPtr` (emscripten with\n * `-fexceptions`).\n * Returns null when the thrown value is neither (a genuine JS error), so the\n * caller rethrows it unchanged.\n */\nfunction nativeExceptionPtr(error: unknown): number | null {\n if (typeof error === 'number') {\n return error;\n }\n if (error !== null && typeof error === 'object') {\n const ptr = (error as { excPtr?: unknown }).excPtr;\n if (typeof ptr === 'number') {\n return ptr;\n }\n }\n return null;\n}\n\n/**\n * Turn a thrown native exception pointer into a {@link SonareError}. The bound\n * `sonareExceptionInfo` decodes the pointer back into { code, codeName,\n * message }.\n */\nfunction makeSonareError(raw: SonareModule, thrown: number): SonareError {\n let code: number = ErrorCode.Unknown;\n let codeName = 'Unknown';\n let message = `libsonare native exception (${thrown})`;\n try {\n const info = (\n raw as unknown as { sonareExceptionInfo?: (ptr: number) => NativeExceptionInfo }\n ).sonareExceptionInfo?.(thrown);\n if (info) {\n code = info.code ?? code;\n codeName = info.codeName ?? codeName;\n message = info.message || message;\n }\n } catch {\n // Fall back to the generic message if decoding fails.\n }\n return new SonareError(code, codeName, message);\n}\n\n/**\n * Wrap the embind module so a native C++ exception (which surfaces as a raw\n * pointer number or a `CppException` carrying one) is rethrown as a\n * {@link SonareError}. Only function-valued\n * members are wrapped, and the wrapper is cached per member so repeated access\n * stays cheap; non-function members (typed-array heap views, etc.) pass through\n * unchanged.\n */\nfunction wrapModuleErrors(raw: SonareModule): SonareModule {\n const cache = new Map<PropertyKey, unknown>();\n const objectCache = new WeakMap<object, unknown>();\n const convert = (error: unknown): never => {\n const ptr = nativeExceptionPtr(error);\n if (ptr !== null) {\n throw makeSonareError(raw, ptr);\n }\n throw error;\n };\n\n const wrapNativeObject = (value: unknown): unknown => {\n if (value === null || typeof value !== 'object') {\n return value;\n }\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer || value instanceof Promise) {\n return value;\n }\n const objectValue = value as object;\n const cached = objectCache.get(objectValue);\n if (cached) {\n return cached;\n }\n const methodCache = new Map<PropertyKey, unknown>();\n const wrapped = new Proxy(objectValue, {\n get(target, prop, receiver) {\n const member = Reflect.get(target, prop, receiver);\n if (typeof member !== 'function') {\n return member;\n }\n const cachedMethod = methodCache.get(prop);\n if (cachedMethod) {\n return cachedMethod;\n }\n const method = member as (...a: unknown[]) => unknown;\n const wrappedMethod = (...args: unknown[]) => {\n try {\n return wrapNativeObject(Reflect.apply(method, target, args));\n } catch (error) {\n return convert(error);\n }\n };\n methodCache.set(prop, wrappedMethod);\n return wrappedMethod;\n },\n });\n objectCache.set(objectValue, wrapped);\n return wrapped;\n };\n\n const wrapFunction = (value: (...a: unknown[]) => unknown): unknown => {\n const fnCache = new Map<PropertyKey, unknown>();\n return new Proxy(value, {\n get(target, prop, receiver) {\n const member = Reflect.get(target, prop, receiver);\n if (typeof member !== 'function') {\n return member;\n }\n const cachedMember = fnCache.get(prop);\n if (cachedMember) {\n return cachedMember;\n }\n const fn = member as (...a: unknown[]) => unknown;\n const wrappedMember = (...args: unknown[]) => {\n try {\n return wrapNativeObject(Reflect.apply(fn, target, args));\n } catch (error) {\n return convert(error);\n }\n };\n fnCache.set(prop, wrappedMember);\n return wrappedMember;\n },\n apply(t, thisArg, args) {\n try {\n return wrapNativeObject(Reflect.apply(t, thisArg, args as unknown[]));\n } catch (error) {\n return convert(error);\n }\n },\n construct(t, args, newTarget) {\n try {\n return wrapNativeObject(Reflect.construct(t, args as unknown[], newTarget)) as object;\n } catch (error) {\n return convert(error) as object;\n }\n },\n });\n };\n\n return new Proxy(raw, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof value !== 'function') {\n return value;\n }\n const cached = cache.get(prop);\n if (cached) {\n return cached;\n }\n // Wrap as a Proxy (not a plain function) so embind class constructors\n // invoked via `new module.Foo(...)` keep their `[[Construct]]` behaviour\n // and prototype while still converting thrown native pointers.\n const wrapped = wrapFunction(value as (...a: unknown[]) => unknown);\n cache.set(prop, wrapped);\n return wrapped;\n },\n }) as SonareModule;\n}\n\nexport function setSonareModule(module: SonareModule): void {\n wrappedModule = wrapModuleErrors(module);\n}\n\nexport function getSonareModule(): SonareModule {\n if (!wrappedModule) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return wrappedModule;\n}\n","/**\n * Per-call validation options accepted by guarded wrappers. Empty-buffer\n * checks are always performed; pass `{ validate: false }` to opt out of the\n * O(n) NaN/Inf scan on hot paths.\n *\n * `{ validate: false }` only skips this JS-side pre-scan (which raises a\n * `RangeError` naming the exact offending index). It is NOT a way to push\n * non-finite samples into the core: the native layer always re-validates the\n * buffer (see `validate_offline_audio_input` in the C++ core), matching the C\n * ABI / Node / Python surfaces, so an NaN/Inf buffer still throws — just with a\n * generic native message instead of the indexed JS one.\n */\nexport interface ValidateOptions {\n validate?: boolean;\n}\n\n/**\n * Offline-analysis sample-rate bounds, mirroring the C++ core limits\n * (`sonare::kMinAudioSampleRate` / `kMaxAudioSampleRate` in `core/audio.h`).\n * Every guarded WASM entry point rejects the same out-of-range rates the C ABI,\n * Node, and Python surfaces do.\n */\nexport const MIN_AUDIO_SAMPLE_RATE = 8000;\nexport const MAX_AUDIO_SAMPLE_RATE = 384000;\n\nfunction assertNonEmptySamples(\n fnName: string,\n samples: ArrayLike<number>,\n argName = 'samples',\n): void {\n if (samples.length === 0) {\n throw new RangeError(`${fnName}: ${argName} must not be empty`);\n }\n}\n\nfunction assertFiniteSamples(\n fnName: string,\n samples: ArrayLike<number>,\n validate: boolean,\n argName = 'samples',\n): void {\n if (!validate) {\n return;\n }\n for (let i = 0; i < samples.length; i++) {\n const v = samples[i] as number;\n if (!Number.isFinite(v)) {\n throw new RangeError(`${fnName}: ${argName} contains NaN or Inf at index ${i}`);\n }\n }\n}\n\nexport function assertSamples(\n fnName: string,\n samples: ArrayLike<number>,\n validate: boolean,\n argName = 'samples',\n): void {\n assertNonEmptySamples(fnName, samples, argName);\n assertFiniteSamples(fnName, samples, validate, argName);\n}\n\nexport function assertFiniteScalar(fnName: string, value: number, argName: string): void {\n if (!Number.isFinite(value)) {\n throw new RangeError(`${fnName}: ${argName} must be a finite number`);\n }\n}\n\nexport function assertSampleRate(fnName: string, sampleRate: number): void {\n if (\n !Number.isInteger(sampleRate) ||\n sampleRate < MIN_AUDIO_SAMPLE_RATE ||\n sampleRate > MAX_AUDIO_SAMPLE_RATE\n ) {\n throw new RangeError(\n `${fnName}: sampleRate out of supported range [${MIN_AUDIO_SAMPLE_RATE}, ${MAX_AUDIO_SAMPLE_RATE}]`,\n );\n }\n}\n\n/** Validate and retain the public Audio.fromBuffer construction contract. */\nexport function validateAudioBuffer(samples: Float32Array, sampleRate: number): void {\n assertSamples('Audio.fromBuffer', samples, true);\n assertSampleRate('Audio.fromBuffer', sampleRate);\n}\n\nexport function assertNonNegativeInteger(fnName: string, value: number, argName: string): void {\n if (!Number.isInteger(value) || value < 0) {\n throw new RangeError(`${fnName}: ${argName} must be a non-negative integer`);\n }\n}\n\nexport function assertPositiveInteger(fnName: string, value: number, argName: string): void {\n if (!Number.isInteger(value) || value <= 0) {\n throw new RangeError(`${fnName}: ${argName} must be a positive integer`);\n }\n}\n\nexport function assertInterleavedSamples(\n fnName: string,\n samples: ArrayLike<number>,\n channels: number,\n validate: boolean,\n): void {\n assertSamples(fnName, samples, validate);\n assertPositiveInteger(fnName, channels, 'channels');\n if (samples.length % channels !== 0) {\n throw new RangeError(`${fnName}: samples length must be a multiple of channels`);\n }\n}\n","import type { MasteringChainConfig } from './public_types';\n\ntype ChainSection = { [key: string]: number | boolean | ChainSection | undefined };\n\n/**\n * Flattens a nested {@link MasteringChainConfig} into the dot-notation\n * `{ \"module.processor.param\": value }` map the core consumes. Internal helper\n * shared by the mastering-chain / master-audio entry points. The core owns\n * legacy leaf-name aliases, so this remains a structural flattening step.\n *\n * A key the caller already wrote in dot notation carries through untouched, so\n * both spellings a {@link MasteringChainConfig} accepts reach the core as the\n * same parameter — matching what the Python binding documents. An unknown key\n * in either spelling is rejected by the core, not here.\n */\nexport function flattenChainConfig(config: MasteringChainConfig): Record<string, number | boolean> {\n const out: Record<string, number | boolean> = {};\n const walk = (node: ChainSection, prefix: string): void => {\n for (const [key, value] of Object.entries(node)) {\n const path = prefix ? `${prefix}.${key}` : key;\n if (typeof value === 'number' || typeof value === 'boolean') {\n out[path] = value;\n } else if (value !== null && typeof value === 'object') {\n walk(value, path);\n } else if (value !== undefined) {\n throw new TypeError(`Mastering override '${path}' must be a number or boolean.`);\n }\n }\n };\n walk(config as ChainSection, '');\n\n return out;\n}\n","import { flattenChainConfig } from './_chain_config';\nimport { getSonareModule } from './module_state';\nimport type {\n MasteringChainConfig,\n MasteringChainResult,\n MasteringChainStereoResult,\n MasteringPreset,\n} from './public_types';\nimport type { ProgressCallback } from './sonare.js';\n\nfunction requireModule() {\n return getSonareModule();\n}\n\n/** Internal envelope selecting the core dotted-param parser in the embind layer. */\nfunction canonicalChainConfig(config: MasteringChainConfig): Record<string, unknown> {\n return { __flatParams: flattenChainConfig(config) };\n}\n\nexport interface MasteringChainRequest {\n samples: Float32Array;\n sampleRate?: number;\n config?: MasteringChainConfig;\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n}\n\nexport interface MasteringChainStereoRequest {\n left: Float32Array;\n right: Float32Array;\n sampleRate?: number;\n config?: MasteringChainConfig;\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n}\n\n/** Canonical request form for one-shot preset mastering. */\nexport interface MasterAudioRequest {\n samples: Float32Array;\n sampleRate?: number;\n preset?: MasteringPreset;\n overrides?: MasteringChainConfig;\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n}\n\n/** Canonical request form for one-shot stereo preset mastering. */\nexport interface MasterAudioStereoRequest {\n left: Float32Array;\n right: Float32Array;\n sampleRate?: number;\n preset?: MasteringPreset;\n overrides?: MasteringChainConfig;\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n}\n\nfunction masterAudioRequest(\n requestOrSamples: MasterAudioRequest | Float32Array,\n sampleRate: number,\n preset: MasteringPreset,\n overrides: MasteringChainConfig | null,\n onProgress?: ProgressCallback,\n): MasterAudioRequest {\n if (requestOrSamples instanceof Float32Array) {\n return {\n samples: requestOrSamples,\n sampleRate,\n preset,\n overrides: overrides ?? {},\n onProgress,\n };\n }\n return requestOrSamples;\n}\n\nfunction masterAudioStereoRequest(\n requestOrLeft: MasterAudioStereoRequest | Float32Array,\n right: Float32Array | undefined,\n sampleRate: number,\n preset: MasteringPreset,\n overrides: MasteringChainConfig | null,\n onProgress?: ProgressCallback,\n): MasterAudioStereoRequest {\n if (requestOrLeft instanceof Float32Array) {\n return {\n left: requestOrLeft,\n right: right as Float32Array,\n sampleRate,\n preset,\n overrides: overrides ?? {},\n onProgress,\n };\n }\n return requestOrLeft;\n}\n\n/**\n * Apply a configurable mastering chain in WASM.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param config - Chain stage configuration\n * @returns Processed audio, loudness metadata, and applied stage names\n */\nexport function masteringChain(request: MasteringChainRequest): MasteringChainResult;\nexport function masteringChain(\n samples: Float32Array,\n sampleRate?: number,\n config?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainResult;\nexport function masteringChain(\n samples: Float32Array | MasteringChainRequest,\n sampleRate = 22050,\n config: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainResult {\n const request =\n samples instanceof Float32Array ? { samples, sampleRate, config, onProgress } : samples;\n if (request.onProgress || request.cancel) {\n return requireModule().masteringChainWithProgress(\n request.samples,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n }\n return requireModule().masteringChain(\n request.samples,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n );\n}\n\n/**\n * Apply a configurable stereo mastering chain in WASM.\n *\n * @param left - Left channel samples\n * @param right - Right channel samples\n * @param sampleRate - Sample rate in Hz\n * @param config - Chain stage configuration\n * @returns Processed stereo audio, loudness metadata, and applied stage names\n */\nexport function masteringChainStereo(\n request: MasteringChainStereoRequest,\n): MasteringChainStereoResult;\nexport function masteringChainStereo(\n left: Float32Array,\n right: Float32Array,\n sampleRate?: number,\n config?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult;\nexport function masteringChainStereo(\n left: Float32Array | MasteringChainStereoRequest,\n right?: Float32Array,\n sampleRate = 22050,\n config: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult {\n const request =\n left instanceof Float32Array\n ? { left, right: right as Float32Array, sampleRate, config, onProgress }\n : left;\n if (request.left.length !== request.right.length) {\n throw new Error('Stereo channel lengths must match.');\n }\n if (request.onProgress || request.cancel) {\n return requireModule().masteringChainStereoWithProgress(\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n }\n return requireModule().masteringChainStereo(\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n );\n}\n\n/**\n * Apply a configurable mastering chain in WASM with progress reporting.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param config - Chain stage configuration\n * @param onProgress - Progress callback (progress: 0-1, stage: string)\n * @returns Processed audio, loudness metadata, and applied stage names\n */\nexport function masteringChainWithProgress(\n request: MasteringChainRequest & Required<Pick<MasteringChainRequest, 'onProgress'>>,\n): MasteringChainResult;\nexport function masteringChainWithProgress(\n samples: Float32Array,\n sampleRate?: number,\n config?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainResult;\nexport function masteringChainWithProgress(\n samples: Float32Array | MasteringChainRequest,\n sampleRate = 22050,\n config: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainResult {\n const request =\n samples instanceof Float32Array ? { samples, sampleRate, config, onProgress } : samples;\n if (!request.onProgress) {\n throw new TypeError('masteringChainWithProgress: onProgress is required');\n }\n return requireModule().masteringChainWithProgress(\n request.samples,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n request.onProgress,\n request.cancel ?? (() => false),\n );\n}\n\n/**\n * Apply a configurable stereo mastering chain in WASM with progress reporting.\n *\n * @param left - Left channel samples\n * @param right - Right channel samples\n * @param sampleRate - Sample rate in Hz\n * @param config - Chain stage configuration\n * @param onProgress - Progress callback (progress: 0-1, stage: string)\n * @returns Processed stereo audio, loudness metadata, and applied stage names\n */\nexport function masteringChainStereoWithProgress(\n request: MasteringChainStereoRequest & Required<Pick<MasteringChainStereoRequest, 'onProgress'>>,\n): MasteringChainStereoResult;\nexport function masteringChainStereoWithProgress(\n left: Float32Array,\n right: Float32Array,\n sampleRate?: number,\n config?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult;\nexport function masteringChainStereoWithProgress(\n left: Float32Array | MasteringChainStereoRequest,\n right?: Float32Array,\n sampleRate = 22050,\n config: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult {\n const request =\n left instanceof Float32Array\n ? { left, right: right as Float32Array, sampleRate, config, onProgress }\n : left;\n if (!request.onProgress) {\n throw new TypeError('masteringChainStereoWithProgress: onProgress is required');\n }\n if (request.left.length !== request.right.length) {\n throw new Error('Stereo channel lengths must match.');\n }\n return requireModule().masteringChainStereoWithProgress(\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n request.onProgress,\n request.cancel ?? (() => false),\n );\n}\n\n/**\n * List built-in mastering preset identifiers.\n *\n * @returns Preset names in display order (e.g. \"pop\", \"edm\", \"aiMusic\")\n */\nexport function masteringPresetNames(): MasteringPreset[] {\n return Array.from(requireModule().masteringPresetNames()) as MasteringPreset[];\n}\n\n/**\n * Apply a named mastering preset chain to mono audio.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param presetName - Preset identifier from {@link masteringPresetNames}\n * @param overrides - Optional nested {@link MasteringChainConfig} applied on top of the preset (e.g. `{ loudness: { targetLufs: -14 } }`). Pass `null` for preset defaults.\n * @param onProgress - Optional per-stage progress callback (progress: 0-1, stage: string).\n * @returns Processed audio, loudness metadata, and applied stage names\n */\nexport function masterAudio(request: MasterAudioRequest): MasteringChainResult;\nexport function masterAudio(\n samples: Float32Array,\n sampleRate?: number,\n presetName?: MasteringPreset,\n overrides?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainResult;\nexport function masterAudio(\n samples: MasterAudioRequest | Float32Array,\n sampleRate = 22050,\n presetName: MasteringPreset = 'pop',\n overrides: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainResult {\n const request = masterAudioRequest(samples, sampleRate, presetName, overrides, onProgress);\n const flat = flattenChainConfig(request.overrides ?? {});\n if (request.onProgress || request.cancel) {\n return requireModule().masterAudioWithProgress(\n request.preset ?? 'pop',\n request.samples,\n request.sampleRate ?? 22050,\n flat,\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n }\n return requireModule().masterAudio(\n request.preset ?? 'pop',\n request.samples,\n request.sampleRate ?? 22050,\n flat,\n );\n}\n\n/**\n * Apply a named mastering preset chain to stereo audio.\n *\n * @param left - Left channel samples\n * @param right - Right channel samples\n * @param sampleRate - Sample rate in Hz\n * @param presetName - Preset identifier from {@link masteringPresetNames}\n * @param overrides - Optional nested {@link MasteringChainConfig} applied on top of the preset (e.g. `{ loudness: { targetLufs: -14 } }`). Pass `null` for preset defaults.\n * @param onProgress - Optional per-stage progress callback (progress: 0-1, stage: string).\n * @returns Processed stereo audio, loudness metadata, and applied stage names\n */\nexport function masterAudioStereo(request: MasterAudioStereoRequest): MasteringChainStereoResult;\nexport function masterAudioStereo(\n left: Float32Array,\n right: Float32Array,\n sampleRate?: number,\n presetName?: MasteringPreset,\n overrides?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult;\nexport function masterAudioStereo(\n left: MasterAudioStereoRequest | Float32Array,\n right: Float32Array | undefined = undefined,\n sampleRate = 22050,\n presetName: MasteringPreset = 'pop',\n overrides: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult {\n const request = masterAudioStereoRequest(\n left,\n right,\n sampleRate,\n presetName,\n overrides,\n onProgress,\n );\n const flat = flattenChainConfig(request.overrides ?? {});\n if (request.left.length !== request.right.length) {\n throw new Error('Stereo channel lengths must match.');\n }\n if (request.onProgress || request.cancel) {\n return requireModule().masterAudioStereoWithProgress(\n request.preset ?? 'pop',\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n flat,\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n }\n return requireModule().masterAudioStereo(\n request.preset ?? 'pop',\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n flat,\n );\n}\n\n/**\n * Mono `masterAudio` with per-stage progress reporting. `onProgress` is invoked\n * with `(progress, stage)` between each chain stage (progress is in [0,1]).\n */\nexport function masterAudioWithProgress(\n request: MasterAudioRequest & Required<Pick<MasterAudioRequest, 'onProgress'>>,\n): MasteringChainResult;\nexport function masterAudioWithProgress(\n samples: Float32Array,\n sampleRate?: number,\n presetName?: MasteringPreset,\n overrides?: MasteringChainConfig | null,\n onProgress?: ProgressCallback,\n): MasteringChainResult;\nexport function masterAudioWithProgress(\n samples: MasterAudioRequest | Float32Array,\n sampleRate = 22050,\n presetName: MasteringPreset = 'pop',\n overrides: MasteringChainConfig | null = null,\n onProgress?: ProgressCallback,\n): MasteringChainResult {\n const request = masterAudioRequest(samples, sampleRate, presetName, overrides, onProgress);\n if (!request.onProgress) {\n throw new TypeError('masterAudioWithProgress: onProgress is required');\n }\n return requireModule().masterAudioWithProgress(\n request.preset ?? 'pop',\n request.samples,\n request.sampleRate ?? 22050,\n flattenChainConfig(request.overrides ?? {}),\n request.onProgress,\n request.cancel ?? (() => false),\n );\n}\n\n/**\n * Stereo `masterAudio` with per-stage progress reporting.\n */\nexport function masterAudioStereoWithProgress(\n request: MasterAudioStereoRequest & Required<Pick<MasterAudioStereoRequest, 'onProgress'>>,\n): MasteringChainStereoResult;\nexport function masterAudioStereoWithProgress(\n left: Float32Array,\n right: Float32Array,\n sampleRate?: number,\n presetName?: MasteringPreset,\n overrides?: MasteringChainConfig | null,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult;\nexport function masterAudioStereoWithProgress(\n left: MasterAudioStereoRequest | Float32Array,\n right: Float32Array | undefined = undefined,\n sampleRate = 22050,\n presetName: MasteringPreset = 'pop',\n overrides: MasteringChainConfig | null = null,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult {\n const request = masterAudioStereoRequest(\n left,\n right,\n sampleRate,\n presetName,\n overrides,\n onProgress,\n );\n if (!request.onProgress) {\n throw new TypeError('masterAudioStereoWithProgress: onProgress is required');\n }\n if (request.left.length !== request.right.length) {\n throw new Error('Stereo channel lengths must match.');\n }\n return requireModule().masterAudioStereoWithProgress(\n request.preset ?? 'pop',\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n flattenChainConfig(request.overrides ?? {}),\n request.onProgress,\n request.cancel ?? (() => false),\n );\n}\n","import type { AutomationCurve, MeterTap, PanLawInput, PanMode, SendTiming } from './public_types';\n\n/** Resolve a numeric ordinal in an inclusive range without coercion. */\nexport function resolveOrdinalInRange(\n value: unknown,\n min: number,\n max: number,\n enumName: string,\n): number {\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < min || value > max) {\n throw new RangeError(`Invalid ${enumName}: ${String(value)}`);\n }\n return value;\n}\n\n/** Resolve a public enum spelling or ordinal without permitting unknown values. */\nexport function resolveEnumOrdinal(\n value: unknown,\n values: Readonly<Record<string, number>>,\n enumName: string,\n): number {\n if (typeof value === 'number') {\n const ordinals = Object.values(values);\n const ordinal = resolveOrdinalInRange(\n value,\n Math.min(...ordinals),\n Math.max(...ordinals),\n enumName,\n );\n if (!ordinals.includes(ordinal)) {\n throw new RangeError(`Invalid ${enumName}: ${String(value)}`);\n }\n return ordinal;\n }\n if (typeof value === 'string') {\n const ordinal = values[value];\n if (ordinal !== undefined) {\n return ordinal;\n }\n }\n throw new RangeError(`Invalid ${enumName}: ${String(value)}`);\n}\n\nconst AUTOMATION_CURVE_VALUES = {\n linear: 0,\n exponential: 1,\n hold: 2,\n 's-curve': 3,\n} as const;\nconst PAN_LAW_VALUES: Readonly<Record<string, number>> = {\n const3db: 0,\n 'const-3db': 0,\n '-3db': 0,\n 'const4.5db': 1,\n 'const-4.5db': 1,\n '-4.5db': 1,\n const6db: 2,\n 'const-6db': 2,\n '-6db': 2,\n linear0db: 3,\n 'linear-0db': 3,\n linear: 3,\n '0db': 3,\n} as const;\nconst PAN_MODE_VALUES = {\n balance: 0,\n pan: 1,\n stereopan: 1,\n 'stereo-pan': 1,\n dualpan: 2,\n 'dual-pan': 2,\n} as const;\nconst METER_TAP_VALUES = { preFader: 0, postFader: 1 } as const;\nconst SEND_TIMING_VALUES = { postFader: 0, preFader: 1 } as const;\nconst TRACK_MONITOR_MODE_VALUES = { off: 0, pfl: 1, afl: 2 } as const;\n\nexport function automationCurveCode(curve: AutomationCurve): number {\n return resolveEnumOrdinal(curve, AUTOMATION_CURVE_VALUES, 'automation curve');\n}\n\nexport function panLawCode(panLaw: PanLawInput): number {\n const normalized = typeof panLaw === 'string' ? panLaw.toLowerCase().replace(/_/g, '-') : panLaw;\n return resolveEnumOrdinal(normalized, PAN_LAW_VALUES, 'pan law');\n}\n\nexport function panModeCode(panMode: PanMode | number): number {\n const normalized =\n typeof panMode === 'string' ? panMode.replace(/_/g, '-').toLowerCase() : panMode;\n return resolveEnumOrdinal(normalized, PAN_MODE_VALUES, 'pan mode');\n}\n\nexport function meterTapCode(tap: MeterTap | number): number {\n return resolveEnumOrdinal(tap, METER_TAP_VALUES, 'meter tap');\n}\n\nexport function sendTimingCode(timing: SendTiming | number): number {\n // Mirrors SonareSendTiming: post-fader is 0 (so an omitted/zeroed value is\n // post-fader), pre-fader is 1. A raw number is passed through as the C ABI int.\n // An unknown string is rejected rather than silently routed to post-fader,\n // matching the sibling enum-code helpers and Node's sendTimingValue.\n return resolveEnumOrdinal(timing, SEND_TIMING_VALUES, 'send timing');\n}\n\n/** Resolve a per-track PFL/AFL monitor mode to its C-ABI ordinal. */\nexport function trackMonitorModeCode(mode: unknown): number {\n return resolveEnumOrdinal(mode, TRACK_MONITOR_MODE_VALUES, 'track monitor mode');\n}\n","import type { ValidateOptions } from './validation';\n\n/**\n * Pitch class enum (C=0, C#=1, ..., B=11)\n */\nexport const PitchClass = {\n C: 0,\n Cs: 1,\n D: 2,\n Ds: 3,\n E: 4,\n F: 5,\n Fs: 6,\n G: 7,\n Gs: 8,\n A: 9,\n As: 10,\n B: 11,\n} as const;\n\nexport type PitchClass = (typeof PitchClass)[keyof typeof PitchClass];\n\n/**\n * Musical mode\n */\nexport const Mode = {\n Major: 0,\n Minor: 1,\n Dorian: 2,\n Phrygian: 3,\n Lydian: 4,\n Mixolydian: 5,\n Locrian: 6,\n} as const;\n\nexport type Mode = (typeof Mode)[keyof typeof Mode];\n\nexport type TempogramMode = 'autocorrelation' | 'auto' | 'ac' | 'cosine' | 0 | 1;\n\nexport const KeyProfile = {\n KrumhanslSchmuckler: 0,\n Temperley: 1,\n Shaath: 2,\n FaraldoEDMT: 3,\n FaraldoEDMA: 4,\n FaraldoEDMM: 5,\n BellmanBudge: 6,\n} as const;\n\nexport type KeyProfile = (typeof KeyProfile)[keyof typeof KeyProfile];\n\nexport type KeyProfileName =\n | 'ks'\n | 'krumhansl'\n | 'temperley'\n | 'shaath'\n | 'keyfinder'\n | 'faraldo-edmt'\n | 'edmt'\n | 'faraldo-edma'\n | 'edma'\n | 'faraldo-edmm'\n | 'edmm'\n | 'bellman-budge'\n | 'bellman';\n\n/**\n * Chord quality\n */\nexport const ChordQuality = {\n Major: 0,\n Minor: 1,\n Diminished: 2,\n Augmented: 3,\n Dominant7: 4,\n Major7: 5,\n Minor7: 6,\n Sus2: 7,\n Sus4: 8,\n Unknown: 9,\n Add9: 10,\n MinorAdd9: 11,\n Dim7: 12,\n HalfDim7: 13,\n Major9: 14,\n Dominant9: 15,\n Sus2Add4: 16,\n} as const;\n\nexport type ChordQuality = (typeof ChordQuality)[keyof typeof ChordQuality];\n\n/**\n * Section type\n */\nexport const SectionType = {\n Intro: 0,\n Verse: 1,\n PreChorus: 2,\n Chorus: 3,\n Bridge: 4,\n Instrumental: 5,\n Outro: 6,\n Unknown: 7,\n} as const;\n\nexport type SectionType = (typeof SectionType)[keyof typeof SectionType];\n\n/**\n * Detected musical key\n */\nexport interface Key {\n root: PitchClass;\n mode: Mode;\n confidence: number;\n name: string;\n shortName: string;\n}\n\nexport interface KeyDetectionOptions extends ValidateOptions {\n nFft?: number;\n hopLength?: number;\n useHpss?: boolean;\n loudnessWeighted?: boolean;\n highPassHz?: number;\n modes?:\n | Mode[]\n | ('major' | 'minor' | 'dorian' | 'phrygian' | 'lydian' | 'mixolydian' | 'locrian')[]\n | 'major-minor'\n | 'all'\n | 'modal';\n profile?: KeyProfile | KeyProfileName;\n genreHint?: 'auto' | 'edm' | 'electronic' | 'dance' | 'pop' | 'classical' | 'jazz' | string;\n}\n\nexport interface KeyCandidate {\n key: Key;\n correlation: number;\n}\n\nexport interface ChordDetectionOptions extends ValidateOptions {\n minDuration?: number;\n smoothingWindow?: number;\n /** Final-template correlation threshold in [0, 1]; below it emits Unknown / N.C. */\n threshold?: number;\n useTriadsOnly?: boolean;\n nFft?: number;\n hopLength?: number;\n useBeatSync?: boolean;\n useHmm?: boolean;\n hmmBeamWidth?: number;\n useKeyContext?: boolean;\n keyRoot?: PitchClass;\n keyMode?: Mode;\n detectInversions?: boolean;\n chromaMethod?: 'stft' | 'nnls';\n}\n\n/** Options for `analyzeBpm`. All fields are optional. */\nexport interface AnalyzeBpmOptions extends ValidateOptions {\n /** Lowest BPM to consider. Default 30. */\n bpmMin?: number;\n /** Highest BPM to consider. Default 300. */\n bpmMax?: number;\n /** Tempo prior the tracker is biased toward. Default 120. */\n startBpm?: number;\n /** FFT size for the onset envelope. Default 2048. */\n nFft?: number;\n /** Hop length for the onset envelope. Default 512. */\n hopLength?: number;\n /** Number of tempo candidates to return. Default 5. */\n maxCandidates?: number;\n}\n\n/** Options for `analyzeRhythm`. All fields are optional. */\nexport interface AnalyzeRhythmOptions extends ValidateOptions {\n /** Lowest BPM to consider. Default 60. */\n bpmMin?: number;\n /** Highest BPM to consider. Default 200. */\n bpmMax?: number;\n /** Tempo prior the tracker is biased toward. Default 120. */\n startBpm?: number;\n /** FFT size for the onset envelope. Default 2048. */\n nFft?: number;\n /** Hop length for the onset envelope. Default 512. */\n hopLength?: number;\n}\n\n/** Options for `analyzeDynamics`. All fields are optional. */\nexport interface AnalyzeDynamicsOptions extends ValidateOptions {\n /** Loudness-curve window length in seconds. Default 0.4. */\n windowSec?: number;\n /** Hop length for the loudness curve. Default 512. */\n hopLength?: number;\n /** Crest-factor (dB) below which the signal is flagged as compressed. Default 6. */\n compressionThreshold?: number;\n}\n\n/** Options for `analyzeTimbre`. All fields are optional. */\nexport interface AnalyzeTimbreOptions extends ValidateOptions {\n /** FFT size. Default 2048. */\n nFft?: number;\n /** Hop length. Default 512. */\n hopLength?: number;\n /** Number of Mel bands. Default 128. */\n nMels?: number;\n /** Number of MFCCs. Default 13. */\n nMfcc?: number;\n /** Per-window analysis length in seconds. Default 0.5. */\n windowSec?: number;\n}\n\n/** Options for `analyzeSections`. All fields are optional. */\nexport interface AnalyzeSectionsOptions {\n /** FFT size. Default 2048. */\n nFft?: number;\n /** Hop length. Default 512. */\n hopLength?: number;\n /** Minimum section duration in seconds. Default 4. */\n minSectionSec?: number;\n}\n\n/**\n * Detected beat\n */\nexport interface Beat {\n time: number;\n strength: number;\n}\n\n/**\n * Detected chord\n */\nexport interface Chord {\n root: PitchClass;\n bass: PitchClass;\n /** Canonical core spelling; stable across all language bindings. */\n rootName: string;\n /** Canonical core spelling; stable across all language bindings. */\n bassName: string;\n quality: ChordQuality;\n start: number;\n end: number;\n confidence: number;\n name: string;\n}\n\nexport interface ChordAnalysisResult {\n chords: Chord[];\n}\n\n/**\n * Detected section\n */\nexport interface Section {\n type: SectionType;\n start: number;\n end: number;\n energyLevel: number;\n confidence: number;\n name: string;\n}\n\n/**\n * A single melody contour point (mirrors the C `SonareMelodyPoint`).\n */\nexport interface MelodyPoint {\n /** Frame time in seconds. */\n time: number;\n /** Estimated fundamental frequency in Hz (0 when unvoiced). */\n frequency: number;\n /** Voicing confidence in `[0, 1]`. */\n confidence: number;\n}\n\n/**\n * Melody analysis result (mirrors the C `SonareMelodyResult`).\n */\nexport interface MelodyResult {\n points: MelodyPoint[];\n pitchRangeOctaves: number;\n pitchStability: number;\n meanFrequency: number;\n vibratoRate: number;\n}\n\n/**\n * Timbre characteristics\n */\nexport interface Timbre {\n brightness: number;\n warmth: number;\n density: number;\n roughness: number;\n complexity: number;\n}\n\n/**\n * Dynamics characteristics\n */\nexport interface Dynamics {\n dynamicRangeDb: number;\n peakDb: number;\n rmsDb: number;\n loudnessRangeDb: number;\n crestFactor: number;\n isCompressed: boolean;\n}\n\n/**\n * Time signature\n */\nexport interface TimeSignature {\n numerator: number;\n denominator: number;\n confidence: number;\n}\n\n/** Existing tempo-estimator hypothesis retained by unified analysis. */\nexport interface BpmHypothesis {\n value: number;\n confidence: number;\n relation: 'primary' | 'half' | 'double' | 'other';\n}\n\n/**\n * Rhythm features\n */\nexport interface RhythmFeatures {\n syncopation: number;\n grooveType: string;\n patternRegularity: number;\n tempoStability: number;\n timeSignature: TimeSignature;\n}\n\n/**\n * Melody contour from the unified analysis (pitch trajectory + summary stats).\n */\nexport interface MelodyContour {\n pitchRangeOctaves: number;\n pitchStability: number;\n meanFrequency: number;\n vibratoRate: number;\n pitches: MelodyPoint[];\n}\n\n/**\n * Complete analysis result\n */\nexport interface AnalysisResult {\n bpm: number;\n bpmConfidence: number;\n bpmCandidates: BpmHypothesis[];\n key: Key;\n timeSignature: TimeSignature;\n timeSignatureCandidates: TimeSignature[];\n beatTimes: Float32Array;\n beats: Beat[];\n chords: Chord[];\n sections: Section[];\n timbre: Timbre;\n dynamics: Dynamics;\n rhythm: RhythmFeatures;\n melody: MelodyContour;\n form: string;\n}\n","import { resolveEnumOrdinal } from './codes';\nimport type {\n AnalysisResult,\n ChordAnalysisResult,\n ChordDetectionOptions,\n ChordQuality,\n KeyCandidate,\n KeyDetectionOptions,\n KeyProfileName,\n PitchClass,\n SectionType,\n} from './public_types';\nimport { KeyProfile as KeyProfileValues, Mode } from './public_types';\nimport type {\n WasmAnalysisResult,\n WasmChordAnalysisResult,\n WasmKeyCandidateResult,\n} from './sonare.js';\n\nconst PITCH_CLASS_NAMES = [\n 'C',\n 'C#',\n 'D',\n 'D#',\n 'E',\n 'F',\n 'F#',\n 'G',\n 'G#',\n 'A',\n 'A#',\n 'B',\n] as const;\n\nfunction pitchClassName(value: number): string {\n return PITCH_CLASS_NAMES[value] ?? 'C';\n}\n\nexport function convertKeyCandidate(wasm: WasmKeyCandidateResult): KeyCandidate {\n return {\n key: {\n root: wasm.key.root as PitchClass,\n mode: wasm.key.mode as Mode,\n confidence: wasm.key.confidence,\n name: wasm.key.name,\n shortName: wasm.key.shortName,\n },\n correlation: wasm.correlation,\n };\n}\n\n// Consolidated spelling -> ordinal tables, resolved through the same\n// resolveEnumOrdinal() primitive as panModeCode/panLawCode/etc. in ./codes.\n// An unmapped string or an out-of-range numeric ordinal throws RangeError\n// instead of silently resolving to `undefined` (which used to reach the WASM\n// layer as a mistyped argument) or passing an unvalidated raw number through.\nconst KEY_MODE_VALUES: Readonly<Record<string, number>> = {\n major: Mode.Major,\n minor: Mode.Minor,\n dorian: Mode.Dorian,\n phrygian: Mode.Phrygian,\n lydian: Mode.Lydian,\n mixolydian: Mode.Mixolydian,\n locrian: Mode.Locrian,\n};\n\nconst KEY_PROFILE_VALUES: Readonly<Record<KeyProfileName, number>> = {\n ks: KeyProfileValues.KrumhanslSchmuckler,\n krumhansl: KeyProfileValues.KrumhanslSchmuckler,\n temperley: KeyProfileValues.Temperley,\n shaath: KeyProfileValues.Shaath,\n keyfinder: KeyProfileValues.Shaath,\n 'faraldo-edmt': KeyProfileValues.FaraldoEDMT,\n edmt: KeyProfileValues.FaraldoEDMT,\n 'faraldo-edma': KeyProfileValues.FaraldoEDMA,\n edma: KeyProfileValues.FaraldoEDMA,\n 'faraldo-edmm': KeyProfileValues.FaraldoEDMM,\n edmm: KeyProfileValues.FaraldoEDMM,\n 'bellman-budge': KeyProfileValues.BellmanBudge,\n bellman: KeyProfileValues.BellmanBudge,\n};\n\nexport function keyModeValues(modes: KeyDetectionOptions['modes'] | undefined): number[] {\n if (!modes) {\n return [];\n }\n if (modes === 'major-minor') {\n return [Mode.Major, Mode.Minor];\n }\n if (modes === 'all' || modes === 'modal') {\n return [\n Mode.Major,\n Mode.Minor,\n Mode.Dorian,\n Mode.Phrygian,\n Mode.Lydian,\n Mode.Mixolydian,\n Mode.Locrian,\n ];\n }\n return modes.map((mode) => resolveEnumOrdinal(mode, KEY_MODE_VALUES, 'key mode'));\n}\n\nexport function keyProfileValue(profile: KeyDetectionOptions['profile'] | undefined): number {\n if (profile === undefined) {\n return -1;\n }\n return resolveEnumOrdinal(profile, KEY_PROFILE_VALUES, 'key profile');\n}\n\nexport function convertChordAnalysisResult(wasm: WasmChordAnalysisResult): ChordAnalysisResult {\n return {\n chords: wasm.chords.map((c) => ({\n root: c.root as PitchClass,\n bass: c.bass as PitchClass,\n rootName: pitchClassName(c.root),\n bassName: pitchClassName(c.bass),\n quality: c.quality as ChordQuality,\n start: c.start,\n end: c.end,\n confidence: c.confidence,\n name: c.name,\n })),\n };\n}\n\nexport function chordChromaMethodValue(method: ChordDetectionOptions['chromaMethod']): number {\n if (method === 'stft') {\n return 0;\n }\n if (method === 'nnls') {\n return 1;\n }\n throw new Error(`Invalid chord chroma method: ${method}`);\n}\n\nexport function convertAnalysisResult(wasm: WasmAnalysisResult): AnalysisResult {\n const beatTimes = new Float32Array(wasm.beats.length);\n for (let i = 0; i < wasm.beats.length; i++) {\n beatTimes[i] = wasm.beats[i].time;\n }\n return {\n bpm: wasm.bpm,\n bpmConfidence: wasm.bpmConfidence,\n bpmCandidates: wasm.bpmCandidates.map((candidate) => ({\n value: candidate.value,\n confidence: candidate.confidence,\n relation: candidate.relation,\n })),\n key: {\n root: wasm.key.root as PitchClass,\n mode: wasm.key.mode as Mode,\n confidence: wasm.key.confidence,\n name: wasm.key.name,\n shortName: wasm.key.shortName,\n },\n timeSignature: wasm.timeSignature,\n timeSignatureCandidates: wasm.timeSignatureCandidates,\n beatTimes,\n beats: wasm.beats,\n chords: wasm.chords.map((c) => ({\n root: c.root as PitchClass,\n bass: c.bass as PitchClass,\n rootName: pitchClassName(c.root),\n bassName: pitchClassName(c.bass),\n quality: c.quality as ChordQuality,\n start: c.start,\n end: c.end,\n confidence: c.confidence,\n name: c.name,\n })),\n sections: wasm.sections.map((s) => ({\n type: s.type as SectionType,\n start: s.start,\n end: s.end,\n energyLevel: s.energyLevel,\n confidence: s.confidence,\n name: s.name,\n })),\n timbre: wasm.timbre,\n dynamics: wasm.dynamics,\n rhythm: wasm.rhythm,\n melody: wasm.melody,\n form: wasm.form,\n };\n}\n","import {\n chordChromaMethodValue,\n convertAnalysisResult,\n convertChordAnalysisResult,\n convertKeyCandidate,\n keyModeValues,\n keyProfileValue,\n} from './analysis_helpers';\nimport { getSonareModule } from './module_state';\nimport type {\n AcousticOptions,\n AcousticResult,\n AnalysisResult,\n AnalyzeBpmOptions,\n AnalyzeDynamicsOptions,\n AnalyzeRhythmOptions,\n AnalyzeTimbreOptions,\n ChordAnalysisResult,\n ChordDetectionOptions,\n Key,\n KeyCandidate,\n KeyDetectionOptions,\n RirResult,\n RirSynthOptions,\n RoomEstimateOptions,\n RoomEstimateResult,\n RoomMorphOptions,\n} from './public_types';\nimport { Mode, PitchClass } from './public_types';\nimport type { ProgressCallback, WasmAcousticResult } from './sonare.js';\nimport type { ValidateOptions } from './validation';\nimport {\n assertFiniteScalar,\n assertNonNegativeInteger,\n assertSampleRate,\n assertSamples,\n} from './validation';\n\nfunction requireModule() {\n return getSonareModule();\n}\n\ntype GuardedOptions = ValidateOptions;\n\n/** Canonical request form for one-shot analysis functions. */\nexport interface SamplesRequest extends GuardedOptions {\n samples: Float32Array;\n sampleRate?: number;\n}\n\n/** Peak-picking configuration for {@link detectOnsets}. */\nexport interface OnsetDetectOptions {\n nFft?: number;\n hopLength?: number;\n threshold?: number;\n preMax?: number;\n postMax?: number;\n preAvg?: number;\n postAvg?: number;\n delta?: number;\n wait?: number;\n backtrack?: boolean;\n backtrackRange?: number;\n}\nexport interface DetectOnsetsRequest extends SamplesRequest, OnsetDetectOptions {}\n\n/** Canonical request form for key detection functions. */\nexport interface DetectKeyRequest extends KeyDetectionOptions, SamplesRequest {}\n\n/** Canonical request form for analysis with synchronous progress reporting. */\nexport interface AnalyzeWithProgressRequest extends SamplesRequest {\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n}\n\n/** Canonical request form for chord detection. */\nexport interface DetectChordsRequest extends ChordDetectionOptions, SamplesRequest {}\n\n/** Canonical request form for functional chord analysis. */\nexport interface ChordFunctionalAnalysisRequest extends DetectChordsRequest {\n keyRoot: PitchClass;\n /** Musical mode; defaults to {@link Mode.Major}. */\n keyMode?: Mode;\n}\n\n/** Canonical request form for impulse-response analysis. */\nexport interface AnalyzeImpulseResponseRequest extends SamplesRequest {\n nOctaveBands?: number;\n minDecayDb?: number;\n}\n\n/** Canonical request form for acoustic analysis. */\nexport interface DetectAcousticRequest extends AcousticOptions, SamplesRequest {}\n\n/** Canonical request form for equivalent-room estimation. */\nexport interface EstimateRoomRequest extends RoomEstimateOptions, SamplesRequest {}\n\n/** Canonical request form for room-reverb morphing. */\nexport interface RoomMorphRequest extends RoomMorphOptions, GuardedOptions {\n samples: Float32Array;\n sampleRate: number;\n}\n\n/** Canonical request forms for detailed music-analysis APIs. */\nexport interface AnalyzeBpmRequest extends AnalyzeBpmOptions, SamplesRequest {}\nexport interface AnalyzeRhythmRequest extends AnalyzeRhythmOptions, SamplesRequest {}\nexport interface AnalyzeDynamicsRequest extends AnalyzeDynamicsOptions, SamplesRequest {}\nexport interface AnalyzeTimbreRequest extends AnalyzeTimbreOptions, SamplesRequest {}\n\nfunction validateAnalysisInput(\n fnName: string,\n samples: Float32Array,\n sampleRate: number,\n options: GuardedOptions = {},\n): void {\n assertSampleRate(fnName, sampleRate);\n assertSamples(fnName, samples, options.validate !== false);\n}\n\n// ============================================================================\n// Quick API (High-level Analysis)\n// ============================================================================\n\n/**\n * Detect BPM from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Detected BPM\n */\nexport function detectBpm(request: SamplesRequest): number;\nexport function detectBpm(\n samples: Float32Array,\n sampleRate?: number,\n options?: GuardedOptions,\n): number;\nexport function detectBpm(\n samples: Float32Array | SamplesRequest,\n sampleRate = 22050,\n options: GuardedOptions = {},\n): number {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectBpm', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().detectBpm(request.samples, request.sampleRate ?? 22050);\n}\n\n/**\n * Detect musical key from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Detected key\n */\nexport function detectKey(request: DetectKeyRequest): Key;\nexport function detectKey(\n samples: Float32Array,\n sampleRate?: number,\n options?: KeyDetectionOptions,\n): Key;\nexport function detectKey(\n samples: Float32Array | DetectKeyRequest,\n sampleRate = 22050,\n options: KeyDetectionOptions = {},\n): Key {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectKey', request.samples, request.sampleRate ?? 22050, request);\n const result = requireModule()._detectKeyWithOptions(\n request.samples,\n request.sampleRate ?? 22050,\n request.nFft ?? 4096,\n request.hopLength ?? 512,\n request.useHpss ?? false,\n request.loudnessWeighted ?? false,\n request.highPassHz ?? 0,\n keyModeValues(request.modes),\n keyProfileValue(request.profile),\n request.genreHint ?? '',\n );\n return {\n root: result.root as PitchClass,\n mode: result.mode as Mode,\n confidence: result.confidence,\n name: result.name,\n shortName: result.shortName,\n };\n}\n\nexport function detectKeyCandidates(request: DetectKeyRequest): KeyCandidate[];\nexport function detectKeyCandidates(\n samples: Float32Array,\n sampleRate?: number,\n options?: KeyDetectionOptions,\n): KeyCandidate[];\nexport function detectKeyCandidates(\n samples: Float32Array | DetectKeyRequest,\n sampleRate = 22050,\n options: KeyDetectionOptions = {},\n): KeyCandidate[] {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput(\n 'detectKeyCandidates',\n request.samples,\n request.sampleRate ?? 22050,\n request,\n );\n // The embind value marshalling returns an array whose constructor is not this\n // realm's Array; chaining .map() onto it propagates that constructor via\n // Symbol.species, leaving a result that structuredClone (and so postMessage to\n // a Worker) rejects with \"could not be cloned\". Array.from() re-roots it as a\n // plain Array before mapping.\n const candidates = requireModule()._detectKeyCandidates(\n request.samples,\n request.sampleRate ?? 22050,\n request.nFft ?? 4096,\n request.hopLength ?? 512,\n request.useHpss ?? false,\n request.loudnessWeighted ?? false,\n request.highPassHz ?? 0,\n keyModeValues(request.modes),\n keyProfileValue(request.profile),\n request.genreHint ?? '',\n );\n return Array.from(candidates, convertKeyCandidate);\n}\n\n/**\n * Detect onset times from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Array of onset times in seconds\n */\nexport function detectOnsets(request: DetectOnsetsRequest): Float32Array;\nexport function detectOnsets(\n samples: Float32Array,\n sampleRate?: number,\n options?: OnsetDetectOptions & GuardedOptions,\n): Float32Array;\nexport function detectOnsets(\n samples: Float32Array | DetectOnsetsRequest,\n sampleRate = 22050,\n options: OnsetDetectOptions & GuardedOptions = {},\n): Float32Array {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectOnsets', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().detectOnsets(request.samples, request.sampleRate ?? 22050, request);\n}\n\n/**\n * Detect beat times from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Array of beat times in seconds\n */\nexport function detectBeats(request: SamplesRequest): Float32Array;\nexport function detectBeats(\n samples: Float32Array,\n sampleRate?: number,\n options?: GuardedOptions,\n): Float32Array;\nexport function detectBeats(\n samples: Float32Array | SamplesRequest,\n sampleRate = 22050,\n options: GuardedOptions = {},\n): Float32Array {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectBeats', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().detectBeats(request.samples, request.sampleRate ?? 22050);\n}\n\n/**\n * Detect downbeat times from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Array of downbeat times in seconds\n */\nexport function detectDownbeats(request: SamplesRequest): Float32Array;\nexport function detectDownbeats(\n samples: Float32Array,\n sampleRate?: number,\n options?: GuardedOptions,\n): Float32Array;\nexport function detectDownbeats(\n samples: Float32Array | SamplesRequest,\n sampleRate = 22050,\n options: GuardedOptions = {},\n): Float32Array {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectDownbeats', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().detectDownbeats(request.samples, request.sampleRate ?? 22050);\n}\n\n/**\n * Detect chords from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param options - Optional chord detection settings\n * @returns Detected chord segments\n */\nexport function detectChords(request: DetectChordsRequest): ChordAnalysisResult;\nexport function detectChords(\n samples: Float32Array,\n sampleRate?: number,\n options?: ChordDetectionOptions,\n): ChordAnalysisResult;\nexport function detectChords(\n samples: Float32Array | DetectChordsRequest,\n sampleRate = 22050,\n options: ChordDetectionOptions = {},\n): ChordAnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectChords', request.samples, request.sampleRate ?? 22050, request);\n const result = requireModule().detectChords(\n request.samples,\n request.sampleRate ?? 22050,\n request.minDuration ?? 0.3,\n request.smoothingWindow ?? 2.0,\n request.threshold ?? 0.5,\n request.useTriadsOnly ?? false,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n request.useBeatSync ?? true,\n request.useHmm ?? false,\n request.hmmBeamWidth ?? 24,\n request.useKeyContext ?? false,\n request.keyRoot ?? PitchClass.C,\n request.keyMode ?? Mode.Major,\n request.detectInversions ?? false,\n chordChromaMethodValue(request.chromaMethod ?? 'stft'),\n );\n return convertChordAnalysisResult(result);\n}\n\n/**\n * Functional (Roman-numeral) harmonic analysis of the detected chord\n * progression, relative to the given key. Mirrors the C-ABI\n * `sonare_chord_functional_analysis` and the Node/Python `chordFunctionalAnalysis`.\n *\n * @returns One Roman-numeral label (e.g. \"I\", \"IV\", \"V\", \"vi\") per detected chord\n */\nexport function chordFunctionalAnalysis(request: ChordFunctionalAnalysisRequest): string[];\nexport function chordFunctionalAnalysis(\n samples: Float32Array,\n keyRoot: PitchClass,\n keyMode?: Mode,\n sampleRate?: number,\n options?: ChordDetectionOptions,\n): string[];\nexport function chordFunctionalAnalysis(\n samples: Float32Array | ChordFunctionalAnalysisRequest,\n keyRoot?: PitchClass,\n keyMode?: Mode,\n sampleRate = 22050,\n options: ChordDetectionOptions = {},\n): string[] {\n const request =\n samples instanceof Float32Array\n ? { samples, keyRoot, keyMode, sampleRate, ...options }\n : samples;\n validateAnalysisInput(\n 'chordFunctionalAnalysis',\n request.samples,\n request.sampleRate ?? 22050,\n request,\n );\n return requireModule().chordFunctionalAnalysis(\n request.samples,\n request.keyRoot as PitchClass,\n request.keyMode ?? Mode.Major,\n request.sampleRate ?? 22050,\n request.minDuration ?? 0.3,\n request.smoothingWindow ?? 2.0,\n request.threshold ?? 0.5,\n request.useTriadsOnly ?? false,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n request.useBeatSync ?? true,\n request.useHmm ?? false,\n request.hmmBeamWidth ?? 24,\n request.useKeyContext ?? false,\n request.detectInversions ?? false,\n chordChromaMethodValue(request.chromaMethod ?? 'stft'),\n );\n}\n\n/**\n * Perform complete music analysis.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Complete analysis result\n *\n * @remarks\n * This call is synchronous and blocks until analysis completes. Unlike the\n * Node binding (which offers `analyzeAsync` on a libuv worker thread), the\n * WASM build runs on a single thread, so there is no non-blocking variant —\n * the DSP pipeline always runs to completion on the calling thread. To keep\n * the UI responsive for long inputs, drive this from a Web Worker and use\n * {@link analyzeWithProgress} to report progress.\n */\nexport interface MusicAnalyzeOptions {\n nFft?: number;\n hopLength?: number;\n bpmMin?: number;\n bpmMax?: number;\n startBpm?: number;\n useTriadsOnly?: boolean;\n useHpss?: boolean;\n chromaHighpassHz?: number;\n useBassWeighted?: boolean;\n chromaHopMultiplier?: number;\n useChordHmm?: boolean;\n useChordKeyContext?: boolean;\n chordHmmBeamWidth?: number;\n detectChordInversions?: boolean;\n}\nexport interface MusicAnalyzeRequest extends SamplesRequest, MusicAnalyzeOptions {}\n\nexport function analyze(request: MusicAnalyzeRequest): AnalysisResult;\nexport function analyze(\n samples: Float32Array,\n sampleRate?: number,\n options?: GuardedOptions & MusicAnalyzeOptions,\n): AnalysisResult;\nexport function analyze(\n samples: Float32Array | MusicAnalyzeRequest,\n sampleRate = 22050,\n options: GuardedOptions & MusicAnalyzeOptions = {},\n): AnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyze', request.samples, request.sampleRate ?? 22050, request);\n const result = requireModule().analyze(request.samples, request.sampleRate ?? 22050, request);\n return convertAnalysisResult(result);\n}\n\nexport function analyzeImpulseResponse(request: AnalyzeImpulseResponseRequest): AcousticResult;\nexport function analyzeImpulseResponse(\n samples: Float32Array,\n sampleRate?: number,\n nOctaveBands?: number,\n minDecayDb?: number,\n): AcousticResult;\nexport function analyzeImpulseResponse(\n samples: Float32Array | AnalyzeImpulseResponseRequest,\n sampleRate = 48000,\n nOctaveBands = 6,\n minDecayDb?: number,\n): AcousticResult {\n const request =\n samples instanceof Float32Array ? { samples, sampleRate, nOctaveBands, minDecayDb } : samples;\n if (request.minDecayDb === null) {\n throw new TypeError('analyzeImpulseResponse: minDecayDb must be a finite number');\n }\n const resolvedMinDecayDb = request.minDecayDb === undefined ? 30.0 : request.minDecayDb;\n assertFiniteScalar('analyzeImpulseResponse', resolvedMinDecayDb, 'minDecayDb');\n if (resolvedMinDecayDb <= 0) {\n throw new RangeError('analyzeImpulseResponse: minDecayDb must be greater than zero');\n }\n validateAnalysisInput(\n 'analyzeImpulseResponse',\n request.samples,\n request.sampleRate ?? 48000,\n request,\n );\n const result: WasmAcousticResult = requireModule().analyzeImpulseResponseEx(\n request.samples,\n request.sampleRate ?? 48000,\n request.nOctaveBands ?? 6,\n resolvedMinDecayDb,\n );\n return result;\n}\n\nexport function detectAcoustic(request: DetectAcousticRequest): AcousticResult;\nexport function detectAcoustic(\n samples: Float32Array,\n sampleRate?: number,\n options?: AcousticOptions,\n): AcousticResult;\nexport function detectAcoustic(\n samples: Float32Array | DetectAcousticRequest,\n sampleRate = 48000,\n options: AcousticOptions = {},\n): AcousticResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectAcoustic', request.samples, request.sampleRate ?? 48000, request);\n const result: WasmAcousticResult = requireModule().detectAcoustic(\n request.samples,\n request.sampleRate ?? 48000,\n request.nOctaveBands ?? 6,\n request.nThirdOctaveSubbands ?? 24,\n request.minDecayDb ?? 30.0,\n request.noiseFloorMarginDb ?? 10.0,\n );\n return result;\n}\n\n/**\n * Synthesize a room impulse response from shoebox geometry. `hasError` is true\n * when the source/listener falls outside the room (the RIR is then empty).\n */\nexport function synthesizeRir(options: RirSynthOptions = {}): RirResult {\n const module = requireModule();\n if (typeof module.synthesizeRir !== 'function') {\n throw new Error('libsonare was built without acoustic-simulation support');\n }\n return module.synthesizeRir(options);\n}\n\n/**\n * Estimate an equivalent room (volume/dimensions/absorption/DRR) from a\n * recording or impulse response.\n */\nexport function estimateRoom(request: EstimateRoomRequest): RoomEstimateResult;\nexport function estimateRoom(\n samples: Float32Array,\n sampleRate?: number,\n options?: RoomEstimateOptions,\n): RoomEstimateResult;\nexport function estimateRoom(\n samples: Float32Array | EstimateRoomRequest,\n sampleRate = 48000,\n options: RoomEstimateOptions = {},\n): RoomEstimateResult {\n const module = requireModule();\n if (typeof module.estimateRoom !== 'function') {\n throw new Error('libsonare was built without acoustic-simulation support');\n }\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('estimateRoom', request.samples, request.sampleRate ?? 48000, request);\n return module.estimateRoom(request.samples, request.sampleRate ?? 48000, request);\n}\n\n/**\n * Morph a recording's reverberation toward a target room (creative FX, not\n * dereverberation). Returns the morphed samples (input length plus the target\n * room's reverb tail).\n */\nexport function roomMorph(request: RoomMorphRequest): Float32Array;\nexport function roomMorph(\n samples: Float32Array,\n sampleRate: number,\n options?: RoomMorphOptions,\n): Float32Array;\nexport function roomMorph(\n samples: Float32Array | RoomMorphRequest,\n sampleRate?: number,\n options: RoomMorphOptions = {},\n): Float32Array {\n const module = requireModule();\n if (typeof module.roomMorph !== 'function') {\n throw new Error('libsonare was built without acoustic-simulation support');\n }\n const request =\n samples instanceof Float32Array\n ? { samples, sampleRate: sampleRate as number, ...options }\n : samples;\n validateAnalysisInput('roomMorph', request.samples, request.sampleRate, request);\n return module.roomMorph(request.samples, request.sampleRate, request);\n}\n\n/**\n * Perform complete music analysis with progress reporting.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param onProgress - Progress callback (progress: 0-1, stage: string)\n * @returns Complete analysis result\n */\nexport function analyzeWithProgress(request: AnalyzeWithProgressRequest): AnalysisResult;\nexport function analyzeWithProgress(\n samples: Float32Array,\n sampleRate: number | undefined,\n onProgress: ProgressCallback,\n): AnalysisResult;\nexport function analyzeWithProgress(\n samples: Float32Array | AnalyzeWithProgressRequest,\n sampleRate = 22050,\n onProgress?: ProgressCallback,\n): AnalysisResult {\n const request: AnalyzeWithProgressRequest =\n samples instanceof Float32Array\n ? { samples, sampleRate, onProgress: onProgress as ProgressCallback }\n : samples;\n validateAnalysisInput(\n 'analyzeWithProgress',\n request.samples,\n request.sampleRate ?? 22050,\n request,\n );\n const result = requireModule().analyzeWithProgress(\n request.samples,\n request.sampleRate ?? 22050,\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n return convertAnalysisResult(result);\n}\n\nexport interface BpmCandidate {\n bpm: number;\n confidence: number;\n}\n\nexport interface BpmAnalysisResult {\n bpm: number;\n confidence: number;\n candidates: BpmCandidate[];\n autocorrelation: Float32Array;\n tempogram: Float32Array;\n}\n\nexport interface RhythmAnalysisResult {\n timeSignature: { numerator: number; denominator: number; confidence: number };\n syncopation: number;\n grooveType: string;\n patternRegularity: number;\n tempoStability: number;\n bpm: number;\n beatIntervals: Float32Array;\n}\n\nexport interface DynamicsAnalysisResult {\n dynamicRangeDb: number;\n peakDb: number;\n rmsDb: number;\n crestFactor: number;\n loudnessRangeDb: number;\n isCompressed: boolean;\n /** Loudness curve timestamps (seconds), parallel to {@link loudnessRmsDb}. */\n loudnessTimes: Float32Array;\n /** Loudness curve RMS values (dB), parallel to {@link loudnessTimes}. */\n loudnessRmsDb: Float32Array;\n}\n\n/** Timbre metrics for one analysis window. Entries are ordered by time in `timbreOverTime`. */\nexport interface TimbreFrame {\n brightness: number;\n warmth: number;\n density: number;\n roughness: number;\n complexity: number;\n}\n\nexport interface TimbreAnalysisResult extends TimbreFrame {\n spectralCentroid: Float32Array;\n spectralFlatness: Float32Array;\n spectralRolloff: Float32Array;\n /** Time-varying timbre metrics, one entry per analysis window. */\n timbreOverTime: TimbreFrame[];\n}\n\n/**\n * Detailed BPM analysis (BPM, confidence, alternate candidates, autocorrelation,\n * tempogram). Matches the Node `analyzeBpm` / Python `analyze_bpm` surface.\n */\nexport function analyzeBpm(request: AnalyzeBpmRequest): BpmAnalysisResult;\nexport function analyzeBpm(\n samples: Float32Array,\n sampleRate?: number,\n options?: AnalyzeBpmOptions,\n): BpmAnalysisResult;\nexport function analyzeBpm(\n samples: Float32Array | AnalyzeBpmRequest,\n sampleRate = 22050,\n options: AnalyzeBpmOptions = {},\n): BpmAnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyzeBpm', request.samples, request.sampleRate ?? 22050, request);\n assertNonNegativeInteger('analyzeBpm', request.maxCandidates ?? 5, 'maxCandidates');\n return requireModule().analyzeBpm(\n request.samples,\n request.sampleRate ?? 22050,\n request.bpmMin ?? 30.0,\n request.bpmMax ?? 300.0,\n request.startBpm ?? 120.0,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n request.maxCandidates ?? 5,\n );\n}\n\n/**\n * Detailed rhythm analysis (time signature, groove, syncopation, beat intervals).\n */\nexport function analyzeRhythm(request: AnalyzeRhythmRequest): RhythmAnalysisResult;\nexport function analyzeRhythm(\n samples: Float32Array,\n sampleRate?: number,\n options?: AnalyzeRhythmOptions,\n): RhythmAnalysisResult;\nexport function analyzeRhythm(\n samples: Float32Array | AnalyzeRhythmRequest,\n sampleRate = 22050,\n options: AnalyzeRhythmOptions = {},\n): RhythmAnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyzeRhythm', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().analyzeRhythm(\n request.samples,\n request.sampleRate ?? 22050,\n request.bpmMin ?? 60.0,\n request.bpmMax ?? 200.0,\n request.startBpm ?? 120.0,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n );\n}\n\n/**\n * Dynamics analysis (RMS, peak, crest factor, LRA, loudness curve).\n */\nexport function analyzeDynamics(request: AnalyzeDynamicsRequest): DynamicsAnalysisResult;\nexport function analyzeDynamics(\n samples: Float32Array,\n sampleRate?: number,\n options?: AnalyzeDynamicsOptions,\n): DynamicsAnalysisResult;\nexport function analyzeDynamics(\n samples: Float32Array | AnalyzeDynamicsRequest,\n sampleRate = 22050,\n options: AnalyzeDynamicsOptions = {},\n): DynamicsAnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyzeDynamics', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().analyzeDynamics(\n request.samples,\n request.sampleRate ?? 22050,\n request.windowSec ?? 0.4,\n request.hopLength ?? 512,\n request.compressionThreshold ?? 6.0,\n );\n}\n\n/**\n * Timbre analysis (brightness/warmth/density/roughness/complexity plus spectral\n * features and per-window timbre frames).\n */\nexport function analyzeTimbre(request: AnalyzeTimbreRequest): TimbreAnalysisResult;\nexport function analyzeTimbre(\n samples: Float32Array,\n sampleRate?: number,\n options?: AnalyzeTimbreOptions,\n): TimbreAnalysisResult;\nexport function analyzeTimbre(\n samples: Float32Array | AnalyzeTimbreRequest,\n sampleRate = 22050,\n options: AnalyzeTimbreOptions = {},\n): TimbreAnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyzeTimbre', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().analyzeTimbre(\n request.samples,\n request.sampleRate ?? 22050,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n request.nMels ?? 128,\n request.nMfcc ?? 13,\n request.windowSec ?? 0.5,\n );\n}\n\n/**\n * Whether this WASM build was compiled with FFmpeg support. Mirrors Node /\n * Python `hasFfmpegSupport`. In the published WASM binding this currently\n * always returns `false` (FFmpeg is not bundled into the .wasm), but the API\n * exists so caller code can branch on capabilities portably.\n */\nexport function hasFfmpegSupport(): boolean {\n return requireModule().hasFfmpegSupport();\n}\n","/**\n * sonare - Audio Analysis Library\n *\n * @example\n * ```typescript\n * import { init, detectBpm, detectKey, analyze } from '@libraz/libsonare';\n *\n * await init();\n *\n * // Detect BPM from audio samples\n * const bpm = detectBpm(samples, sampleRate);\n *\n * // Detect musical key\n * const key = detectKey(samples, sampleRate);\n *\n * // Full analysis\n * const result = analyze(samples, sampleRate);\n * ```\n */\n\nimport { setSonareModule } from './module_state';\nimport type {\n CapabilityCatalog,\n RealtimeVoiceChangerPodConfig,\n SonareCapabilities,\n VoicePresetId,\n} from './public_types';\nimport type {\n SonareModule,\n WasmDecomposeResult,\n WasmHpssWithResidualResult,\n WasmMatrix2dResult,\n} from './sonare.js';\n\nexport type { BrowserAudioDecodeOptions } from './audio';\nexport { Audio } from './audio';\nexport type {\n ClipPageStreamerEngine,\n ClipPageStreamerOptions,\n ClipPageStreamerRequest,\n ClipPageStreamSource,\n OpfsClipStream,\n OpfsClipStreamOptions,\n WorkletOpfsClipStreamHost,\n} from './clip_page_streamer';\nexport { attachOpfsClipStream, ClipPageStreamer } from './clip_page_streamer';\nexport type {\n CompressorDetector,\n CompressorOptions,\n DeclickOptions,\n DeclipOptions,\n DecrackleMode,\n DecrackleOptions,\n DehumOptions,\n DenoiseClassicalMode,\n DenoiseClassicalNoiseEstimator,\n DenoiseClassicalOptions,\n DereverbClassicalOptions,\n DynamicsResult,\n GateOptions,\n MasteringChannelPolicy,\n MasteringDynamicsCompressorRequest,\n MasteringDynamicsGateRequest,\n MasteringDynamicsTransientShaperRequest,\n MasteringInsertParamInfo,\n MasteringPairAnalyzeRequest,\n MasteringPairProcessRequest,\n MasteringProcessorCatalogEntry,\n MasteringProcessRequest,\n MasteringProcessStereoRequest,\n MasteringRealtimeCost,\n MasteringRepairDeclickRequest,\n MasteringRepairDeclipRequest,\n MasteringRepairDecrackleRequest,\n MasteringRepairDehumRequest,\n MasteringRepairDenoiseClassicalRequest,\n MasteringRepairDereverbClassicalRequest,\n MasteringRepairTrimSilenceRequest,\n MasteringSamplesParamsRequest,\n MasteringStereoAnalyzeRequest,\n MasteringStereoParamsRequest,\n MasteringStreamingPreviewRequest,\n MasteringStreamingPreviewStereoRequest,\n MixStereoRequest,\n TransientShaperOptions,\n TrimSilenceMode,\n TrimSilenceOptions,\n VoiceChangeOptions,\n VoiceChangeRealtimeOptions,\n VoiceChangeRealtimeRequest,\n VoiceChangeRequest,\n} from './effects_mastering';\nexport {\n harmonic,\n hpss,\n masterAudio,\n masterAudioStereo,\n masterAudioStereoWithProgress,\n masterAudioWithProgress,\n mastering,\n masteringAssistantSuggest,\n masteringAssistantSuggestStereo,\n masteringAudioProfile,\n masteringAudioProfileStereo,\n masteringChain,\n masteringChainStereo,\n masteringChainStereoWithProgress,\n masteringChainWithProgress,\n masteringDynamicsCompressor,\n masteringDynamicsGate,\n masteringDynamicsTransientShaper,\n masteringInsertNames,\n masteringInsertParamInfo,\n masteringInsertParamNames,\n masteringPairAnalysisNames,\n masteringPairAnalyze,\n masteringPairProcess,\n masteringPairProcessorNames,\n masteringPresetNames,\n masteringProcess,\n masteringProcessorCatalog,\n masteringProcessorNames,\n masteringProcessStereo,\n masteringRepairDeclick,\n masteringRepairDeclip,\n masteringRepairDecrackle,\n masteringRepairDehum,\n masteringRepairDenoiseClassical,\n masteringRepairDereverbClassical,\n masteringRepairTrimSilence,\n masteringStereoAnalysisNames,\n masteringStereoAnalyze,\n masteringStreamingPreview,\n masteringStreamingPreviewStereo,\n mixingScenePresetJson,\n mixingScenePresetNames,\n mixStereo,\n normalize,\n noteMove,\n noteStretch,\n percussive,\n pitchCorrectTimevarying,\n pitchCorrectToMidi,\n pitchCorrectToMidiTimevarying,\n pitchShift,\n spectralEdit,\n timeStretch,\n voiceChange,\n voiceChangeRealtime,\n} from './effects_mastering';\nexport type {\n HarmonicRequest,\n HpssRequest,\n NormalizeMode,\n NormalizeRequest,\n NoteMoveRequest,\n NoteStretchRequest,\n PercussiveRequest,\n PitchCorrectTimevaryingRequest,\n PitchCorrectToMidiRequest,\n PitchCorrectToMidiTimevaryingRequest,\n PitchShiftRequest,\n SpectralEditRequest,\n TimeStretchRequest,\n} from './effects_transform';\nexport { ErrorCode, isSonareError, SonareError } from './errors';\nexport type {\n ChirpRequest,\n ClicksRequest,\n CyclicTempogramRequest,\n DbConversionRequest,\n EmphasisRequest,\n FixFramesRequest,\n FixLengthRequest,\n FrameSignalRequest,\n OnsetBacktrackRequest,\n PadCenterRequest,\n PcenRequest,\n PeakPickRequest,\n PlpRequest,\n SilenceRequest,\n TempogramRequest,\n ToneRequest,\n TonnetzRequest,\n VectorNormalizeRequest,\n} from './feature_core';\nexport type {\n AnalyzeMelodyRequest,\n AnalyzeSectionsRequest,\n CqtRequest,\n CqtToAudioRequest,\n FourierTempogramRequest,\n LufsRequest,\n MelodyOptions,\n NnlsChromaRequest,\n OnsetEnvelopeRequest,\n OnsetStrengthMultiRequest,\n TempogramRatioRequest,\n VqtRequest,\n VqtToAudioRequest,\n} from './feature_music';\nexport type {\n NoteSegmentsRequest,\n PiptrackRequest,\n PitchPyinRequest,\n PitchYinRequest,\n} from './feature_pitch';\nexport type { ResampleRequest } from './feature_resample';\nexport type {\n DecomposeRequest,\n DecomposeWithInitRequest,\n Ebur128LoudnessRangeRequest,\n EstimateTuningRequest,\n HpssWithResidualRequest,\n LufsInterleavedRequest,\n NnFilterRequest,\n PhaseVocoderRequest,\n PitchTuningRequest,\n PolyFeaturesRequest,\n RemixRequest,\n SegmentAgglomerativeRequest,\n SegmentCrossSimilarityRequest,\n SegmentLagToRecurrenceRequest,\n SegmentPathEnhanceRequest,\n SegmentRecurrenceMatrixRequest,\n SegmentRecurrenceToLagRequest,\n SegmentSubsegmentRequest,\n SpectralContrastRequest,\n SpectralFrameRequest,\n SpectralRolloffRequest,\n ZeroCrossingRateRequest,\n ZeroCrossingsRequest,\n} from './feature_spectral';\nexport type {\n ChromaSpectrogramRequest,\n GriffinLimRequest,\n MelDeltaRequest,\n MelSpectrogramRequest,\n MelToAudioRequest,\n MelToStftRequest,\n MfccRequest,\n MfccToAudioRequest,\n MfccToMelRequest,\n ReassignedSpectrogramRequest,\n SpectrogramRequest,\n TrimRequest,\n} from './feature_spectrogram';\nexport {\n amplitudeToDb,\n analyzeMelody,\n analyzeSections,\n bassChroma,\n chirp,\n chroma,\n chromaCens,\n chromaCqt,\n clicks,\n cqt,\n cqtToAudio,\n cyclicTempogram,\n dbToAmplitude,\n dbToPower,\n decompose,\n decomposeWithInit,\n deemphasis,\n ebur128LoudnessRange,\n estimateTuning,\n fixFrames,\n fixLength,\n fourierTempogram,\n frameSignal,\n framesToSamples,\n framesToTime,\n griffinLim,\n hpssWithResidual,\n hybridCqt,\n hzToMel,\n hzToMidi,\n hzToNote,\n lufs,\n lufsInterleaved,\n melDelta,\n melSpectrogram,\n melToAudio,\n melToHz,\n melToStft,\n mfcc,\n mfccToAudio,\n mfccToMel,\n midiToHz,\n momentaryLufs,\n nnFilter,\n nnlsChroma,\n noteSegments,\n noteToHz,\n onsetBacktrack,\n onsetEnvelope,\n onsetStrengthMulti,\n padCenter,\n pcen,\n peakPick,\n phaseVocoder,\n piptrack,\n pitchPyin,\n pitchTuning,\n pitchYin,\n plp,\n polyFeatures,\n powerToDb,\n preemphasis,\n pseudoCqt,\n reassignedSpectrogram,\n remix,\n resample,\n rmsEnergy,\n samplesToFrames,\n segmentAgglomerative,\n segmentCrossSimilarity,\n segmentLagToRecurrence,\n segmentPathEnhance,\n segmentRecurrenceMatrix,\n segmentRecurrenceToLag,\n segmentSubsegment,\n shortTermLufs,\n spectralBandwidth,\n spectralCentroid,\n spectralContrast,\n spectralFlatness,\n spectralFlux,\n spectralRolloff,\n splitSilence,\n stft,\n stftDb,\n tempogram,\n tempogramRatio,\n timeToFrames,\n tone,\n tonnetz,\n trim,\n trimSilence,\n vectorNormalize,\n vqt,\n vqtToAudio,\n zeroCrossingRate,\n zeroCrossings,\n} from './features';\nexport type { BindMicrophoneInputOptions, MicrophoneInputBinding } from './live_audio';\nexport { bindMicrophoneInput } from './live_audio';\nexport type {\n MasterAudioRequest,\n MasterAudioStereoRequest,\n MasteringChainRequest,\n MasteringChainStereoRequest,\n} from './mastering_chain';\nexport type { MasteringRequest } from './mastering_core';\nexport type {\n ClippingRegion,\n ClippingReport,\n DynamicRangeReport,\n MeteringDetectClippingOptions,\n MeteringDetectClippingRequest,\n MeteringDynamicRangeOptions,\n MeteringDynamicRangeRequest,\n MeteringSamplesRequest,\n MeteringSilenceRatioRequest,\n MeteringSpectrumFrameRequest,\n MeteringSpectrumRequest,\n MeteringStereoDecimatedRequest,\n MeteringStereoRequest,\n MeteringTruePeakRequest,\n PhaseScopeReport,\n SpectrumOptions,\n SpectrumReport,\n VectorscopeReport,\n WaveformPeakPyramidOptions,\n WaveformPeakPyramidRequest,\n WaveformPeaksOptions,\n WaveformPeaksReport,\n WaveformPeaksRequest,\n} from './metering';\nexport {\n meteringCrestFactorDb,\n meteringCrestFactorDbStereo,\n meteringDcOffset,\n meteringDetectClipping,\n meteringDynamicRange,\n meteringPeakDb,\n meteringPhaseScope,\n meteringPhaseScopeDecimated,\n meteringRmsDb,\n meteringSilenceRatio,\n meteringSpectrum,\n meteringSpectrumFrame,\n meteringStereoCorrelation,\n meteringStereoWidth,\n meteringTruePeakDb,\n meteringVectorscope,\n meteringVectorscopeDecimated,\n waveformPeakPyramid,\n waveformPeaks,\n} from './metering';\nexport type {\n OpfsClipPageProviderBinding,\n OpfsClipPageProviderOptions,\n} from './opfs_clip_pages';\nexport {\n createOpfsClipPageProvider,\n createOpfsClipPageWorker,\n opfsClipPageWorkerSource,\n} from './opfs_clip_pages';\nexport type {\n BuiltinSynthBinding,\n BuiltinSynthConfig,\n BuiltinSynthWaveform,\n ExternalSeparatedStem,\n ExternalSeparatedStemImportRequest,\n ExternalSeparatedStemImportResult,\n MidiCcLearnOptions,\n ProjectAssistSidecar,\n ProjectAssistSidecarInput,\n ProjectAutomationCurve,\n ProjectAutomationLaneDesc,\n ProjectAutomationPoint,\n ProjectAutomationTargetKind,\n ProjectBounceOptions,\n ProjectChordSymbol,\n ProjectClip,\n ProjectClipCompSegment,\n ProjectClipDesc,\n ProjectClipFade,\n ProjectClipTake,\n ProjectCompileResult,\n ProjectFadeCurve,\n ProjectKeySegment,\n ProjectLoopMode,\n ProjectLoopRecordingDesc,\n ProjectLoopRecordingResult,\n ProjectMarker,\n ProjectMidiClipResult,\n ProjectMidiEvent,\n ProjectMidiFxBakeRequest,\n ProjectMidiFxBakeResult,\n ProjectMidiFxPreviewRequest,\n ProjectNotePairValidation,\n ProjectSource,\n ProjectTrack,\n ProjectTrackDesc,\n ProjectTrackKind,\n ProjectWarpAnchor,\n ProjectWarpMapDesc,\n Sf2InstrumentConfig,\n Sf2ProgramStatus,\n SourceBackend,\n SynthBodyType,\n SynthEngineMode,\n SynthEnumTables,\n SynthFilterModel,\n SynthFilterOutput,\n SynthModDestination,\n SynthModRouting,\n SynthModSource,\n SynthOscWaveform,\n SynthPatch,\n} from './project';\nexport {\n AutomationTargetKind,\n BUILTIN_SYNTH_WAVEFORMS,\n EXPECTED_PROJECT_ABI_VERSION,\n MarkerKind,\n PROJECT_AUTOMATION_TARGET_OPAQUE,\n PROJECT_AUTOMATION_TARGET_TRACK_FADER_DB,\n PROJECT_AUTOMATION_TARGET_TRACK_PAN,\n Project,\n projectAbiVersion,\n SYNTH_BODY_TYPES,\n SYNTH_ENGINE_MODES,\n SYNTH_FILTER_MODELS,\n SYNTH_FILTER_OUTPUTS,\n SYNTH_MOD_DESTINATIONS,\n SYNTH_MOD_SOURCES,\n SYNTH_OSC_WAVEFORMS,\n synthEnumTables,\n synthPresetNames,\n synthPresetPatch,\n} from './project';\nexport type {\n AcousticOptions,\n AcousticResult,\n AnalysisResult,\n AnalyzeBpmOptions,\n AnalyzeDynamicsOptions,\n AnalyzeRhythmOptions,\n AnalyzeSectionsOptions,\n AnalyzeTimbreOptions,\n AutomationCurve,\n Beat,\n BpmHypothesis,\n Chord,\n ChordAnalysisResult,\n ChordDetectionOptions,\n ChromaResult,\n CqtResult,\n Dynamics,\n EqBand,\n EqBandPhase,\n EqBandType,\n EqCoeffMode,\n EqMatchOptions,\n EqSpectrumSnapshot,\n EqStereoPlacement,\n GoniometerPoint,\n HpssResult,\n Key,\n KeyCandidate,\n KeyDetectionOptions,\n KeyProfileName,\n LufsResult,\n MasteringChainConfig,\n MasteringChainResult,\n MasteringChainStereoResult,\n MasteringLoudnessSummary,\n MasteringOptions,\n MasteringPreset,\n MasteringProcessorParams,\n MasteringReport,\n MasteringResult,\n MasteringStereoChainResult,\n MasteringStereoResult,\n MelodyPoint,\n MelodyResult,\n MelPowerResult,\n MelSpectrogramResult,\n MeterTap,\n MfccResult,\n MixerProcessResult,\n MixMeterSnapshot,\n MixOptions,\n MixResult,\n NoteSegment,\n NoteStretchOptions,\n PairAnalysis,\n PairProcessor,\n PanLaw,\n PanLawInput,\n PanLawName,\n PanMode,\n PitchCorrectOptions,\n PitchResult,\n RealtimeVoiceChangerConfigInput,\n RealtimeVoiceChangerPodConfig,\n RhythmFeatures,\n RirResult,\n RirSynthOptions,\n RoomEstimateOptions,\n RoomEstimateResult,\n RoomGeometryOptions,\n RoomMorphOptions,\n Section,\n SegmentMatrix,\n SendTiming,\n SoloProcessor,\n SonareCapabilities,\n SpectralEditMode,\n SpectralEditOptions,\n SpectralEditWindow,\n SpectralRegionOp,\n StageGainReduction,\n StereoAnalysis,\n StftPowerResult,\n StftResult,\n StreamingEqualizerConfig,\n StreamingMasteringChainConfig,\n StreamingPlatform,\n StreamingRetuneConfig,\n TempogramMode,\n Timbre,\n TimeSignature,\n VoicedFlags,\n VoicePresetId,\n} from './public_types';\nexport {\n ChordQuality,\n KeyProfile,\n Mode,\n PitchClass,\n SectionType,\n} from './public_types';\nexport type {\n AnalyzeBpmRequest,\n AnalyzeDynamicsRequest,\n AnalyzeImpulseResponseRequest,\n AnalyzeRhythmRequest,\n AnalyzeTimbreRequest,\n AnalyzeWithProgressRequest,\n BpmAnalysisResult,\n BpmCandidate,\n ChordFunctionalAnalysisRequest,\n DetectAcousticRequest,\n DetectChordsRequest,\n DetectKeyRequest,\n DetectOnsetsRequest,\n DynamicsAnalysisResult,\n EstimateRoomRequest,\n MusicAnalyzeRequest,\n RhythmAnalysisResult,\n RoomMorphRequest,\n SamplesRequest,\n TimbreAnalysisResult,\n TimbreFrame,\n} from './quick_analysis';\nexport {\n analyze,\n analyzeBpm,\n analyzeDynamics,\n analyzeImpulseResponse,\n analyzeRhythm,\n analyzeTimbre,\n analyzeWithProgress,\n chordFunctionalAnalysis,\n detectAcoustic,\n detectBeats,\n detectBpm,\n detectChords,\n detectDownbeats,\n detectKey,\n detectKeyCandidates,\n detectOnsets,\n estimateRoom,\n hasFfmpegSupport,\n roomMorph,\n synthesizeRir,\n} from './quick_analysis';\nexport type {\n ClipPageRequest,\n EngineAutomationPoint,\n EngineBounceOptions,\n EngineBounceResult,\n EngineBus,\n EngineCapabilities,\n EngineCaptureSource,\n EngineCaptureStatus,\n EngineClip,\n EngineFreezeOptions,\n EngineFreezeResult,\n EngineGraphSpec,\n EngineMarker,\n EngineMeterTelemetry,\n EngineMeterTelemetryWide,\n EngineMetronomeConfig,\n EngineMidiClipSchedule,\n EngineMidiEvent,\n EngineParameterInfo,\n EngineScopeTelemetry,\n EngineTelemetry,\n EngineTempoSegment,\n EngineTimeSignatureSegment,\n EngineTrackLane,\n EngineTrackMonitorMode,\n EngineTrackSend,\n EngineTransportState,\n ExternalMidiEvent,\n MidiCcBindOptions,\n TrackMonitorMode,\n} from './realtime_engine';\nexport {\n ClipPageProvider,\n EXPECTED_ENGINE_ABI_VERSION,\n engineCapabilities,\n RealtimeEngine,\n} from './realtime_engine';\nexport { scaleCorrectionSemitones, scalePitchClassEnabled, scaleQuantizeMidi } from './scale';\nexport type { ProgressCallback } from './sonare.js';\nexport { StreamAnalyzer, streamAnalyzerConfigDefaults } from './stream_analyzer';\nexport type {\n AnalyzerStats,\n BarChord,\n ChordChange,\n FrameBuffer,\n PatternScore,\n ProgressiveEstimate,\n StreamConfig,\n StreamConfigDefaults,\n StreamFramesI16,\n StreamFramesU8,\n StreamQuantizeConfig,\n} from './stream_types';\nexport type {\n MixerRealtimeBuffer,\n RealtimeVoiceChangerInterleavedBuffer,\n RealtimeVoiceChangerMonoBuffer,\n RealtimeVoiceChangerPlanarBuffer,\n} from './streaming_mixing';\nexport {\n Mixer,\n RealtimeVoiceChanger,\n realtimeVoiceChangerPresetJson,\n realtimeVoiceChangerPresetNames,\n StreamingEqualizer,\n StreamingMasteringChain,\n StreamingRetune,\n validateRealtimeVoiceChangerPresetJson,\n} from './streaming_mixing';\nexport type { ValidateOptions } from './validation';\nexport type {\n BindWebMidiOptions,\n WebMidiBinding,\n WebMidiCcBinding,\n WebMidiInputInfo,\n} from './web_midi';\nexport { bindWebMidi, isWebMidiAvailable } from './web_midi';\nexport type {\n OfflineWorker,\n OfflineWorkerCallOptions,\n OfflineWorkerClientOptions,\n OfflineWorkerProgress,\n} from './worker_client';\nexport { OfflineWorkerClient, OfflineWorkerTask } from './worker_client';\n\n/** Row-major 2-D matrix as a flat buffer plus its dimensions. */\nexport type Matrix2dResult = WasmMatrix2dResult;\n/** NMF factor matrices { w, h } from {@link decompose}. */\nexport type DecomposeResult = WasmDecomposeResult;\n/** Harmonic / percussive / residual signals from {@link hpssWithResidual}. */\nexport type HpssWithResidualResult = WasmHpssWithResidualResult;\n\n// ============================================================================\n// Module State\n// ============================================================================\n\nlet module: SonareModule | null = null;\nlet initPromise: Promise<void> | null = null;\n\n// ============================================================================\n// Initialization\n// ============================================================================\n\n/**\n * Initialize the WASM module.\n * Must be called before using any analysis functions.\n *\n * @param options - Optional module configuration\n * @returns Promise that resolves when initialization is complete\n */\nexport async function init(options?: {\n locateFile?: (path: string, prefix: string) => string;\n wasmBinary?: ArrayBuffer | Uint8Array;\n moduleFactory?: (options?: {\n locateFile?: (path: string, prefix: string) => string;\n wasmBinary?: ArrayBuffer | Uint8Array;\n }) => Promise<SonareModule>;\n}): Promise<void> {\n if (module) {\n return;\n }\n\n if (initPromise) {\n return initPromise;\n }\n\n initPromise = (async () => {\n try {\n const createModule = options?.moduleFactory ?? (await import('./sonare.js')).default;\n module = await createModule(options);\n setSonareModule(module);\n } catch (error) {\n initPromise = null;\n throw error;\n }\n })();\n\n return initPromise;\n}\n\n/**\n * Check if the module is initialized.\n */\nexport function isInitialized(): boolean {\n return module !== null;\n}\n\n/**\n * Get the library version.\n */\nexport function version(): string {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.version();\n}\n\n/**\n * Return the capabilities of the loaded WASM build.\n *\n * This is synchronous and only describes the already-initialized module.\n */\nexport function capabilities(): SonareCapabilities {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.capabilities();\n}\n\n/** Return the initialized module's processors, parameters, and presets. */\nexport function capabilityCatalog(): CapabilityCatalog {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return JSON.parse(module.capabilityCatalog()) as CapabilityCatalog;\n}\n\n/**\n * Aggregate native ABI version: the per-subsystem ABI macros folded into one\n * 32-bit value. It bumps whenever any flat C POD layout changes, so callers can\n * detect an incompatible prebuilt binary. Matches the Node/Python `abiVersion()`.\n */\nexport function abiVersion(): number {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.abiVersion();\n}\n\nexport function engineAbiVersion(): number {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.engineAbiVersion();\n}\n\nexport function voiceChangerAbiVersion(): number {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.voiceChangerAbiVersion();\n}\n\n// Canonical ordinal order of the built-in voice-character presets, matching the\n// C ABI SonareVoiceCharacterPreset enum and SONARE_REALTIME_VOICE_CHANGER_PRESET_IDS.\nconst VOICE_PRESET_ORDINALS: readonly VoicePresetId[] = [\n 'neutral-monitor',\n 'bright-idol',\n 'soft-whisper',\n 'deep-narrator',\n 'robot-mascot',\n 'dark-villain',\n];\n\nfunction resolveVoicePresetOrdinal(preset: VoicePresetId | number): number {\n if (typeof preset === 'number') {\n if (!Number.isSafeInteger(preset) || preset < 0 || preset >= VOICE_PRESET_ORDINALS.length) {\n throw new RangeError(`Unknown voice-character preset ordinal: ${String(preset)}`);\n }\n return preset;\n }\n const ordinal = VOICE_PRESET_ORDINALS.indexOf(preset);\n if (ordinal < 0) {\n throw new Error(`Unknown voice character preset: ${preset}`);\n }\n return ordinal;\n}\n\n/**\n * Map a voice-character preset ordinal (or canonical id) to its canonical id\n * string (e.g. `'bright-idol'`). Unknown numeric ordinals return `null`;\n * unknown preset ids throw.\n */\nexport function voiceCharacterPresetId(preset: VoicePresetId | number): VoicePresetId | null {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n if (\n typeof preset === 'number' &&\n (!Number.isSafeInteger(preset) || preset < 0 || preset >= VOICE_PRESET_ORDINALS.length)\n ) {\n return null;\n }\n return module.voiceCharacterPresetId(resolveVoicePresetOrdinal(preset)) as VoicePresetId;\n}\n\n/**\n * Return the canonical (normalized) flat POD config for a built-in voice\n * preset, skipping the JSON round-trip. Accepts a canonical preset id or its\n * integer ordinal. Invalid ordinals throw.\n */\nexport function realtimeVoiceChangerPresetConfig(\n preset: VoicePresetId | number,\n): RealtimeVoiceChangerPodConfig {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.realtimeVoiceChangerPresetConfig(resolveVoicePresetOrdinal(preset));\n}\n\n// ============================================================================\n// Re-exports\n// ============================================================================\n\nexport { PitchClass as Pitch } from './public_types';\n","/**\n * Offline one-shot operations hosted inside a dedicated Web Worker.\n *\n * Only value-based calls are exposed here: analysis and preset mastering. Do\n * not add `Project`, `Mixer`, or realtime handles. Their native lifetime is\n * bound to one JavaScript realm, so moving them across a Worker boundary would\n * make ownership and `delete()` semantics unsound.\n */\n\nimport { ErrorCode, SonareError } from './errors';\nimport { init } from './index';\nimport type { MasterAudioRequest, MasterAudioStereoRequest } from './mastering_chain';\nimport { masterAudio, masterAudioStereo } from './mastering_chain';\nimport type {\n DetectChordsRequest,\n DetectKeyRequest,\n MusicAnalyzeRequest,\n SamplesRequest,\n} from './quick_analysis';\nimport { analyzeWithProgress, detectBpm, detectChords, detectKey } from './quick_analysis';\nimport type {\n OfflineWorkerErrorMessage,\n OfflineWorkerRequestMessage,\n OfflineWorkerResponseMessage,\n OfflineWorkerRunMessage,\n} from './worker_protocol';\n\nexport type { OfflineWorkerOperation } from './worker_protocol';\n\n/** Minimal endpoint shared by browser Workers and the Node worker-thread test bridge. */\nexport interface OfflineWorkerEndpoint {\n postMessage(message: OfflineWorkerResponseMessage, transfer?: Transferable[]): void;\n addEventListener(\n type: 'message',\n listener: (event: MessageEvent<OfflineWorkerRequestMessage>) => void,\n ): void;\n}\n\nfunction transferableBuffers(value: unknown, seen = new Set<object>()): Transferable[] {\n const buffers: Transferable[] = [];\n const seenBuffers = new Set<ArrayBuffer>();\n const visit = (item: unknown): void => {\n if (item === null || item === undefined || typeof item !== 'object') {\n return;\n }\n if (ArrayBuffer.isView(item)) {\n const buffer = item.buffer;\n if (buffer instanceof ArrayBuffer && !seenBuffers.has(buffer)) {\n seenBuffers.add(buffer);\n buffers.push(buffer);\n }\n return;\n }\n if (item instanceof ArrayBuffer) {\n if (!seenBuffers.has(item)) {\n seenBuffers.add(item);\n buffers.push(item);\n }\n return;\n }\n if (seen.has(item)) {\n return;\n }\n seen.add(item);\n if (Array.isArray(item)) {\n item.forEach(visit);\n return;\n }\n Object.values(item).forEach(visit);\n };\n visit(value);\n return buffers;\n}\n\nfunction errorMessage(error: unknown): OfflineWorkerErrorMessage['error'] {\n if (error instanceof SonareError) {\n return {\n name: error.name,\n message: error.message,\n code: error.code,\n codeName: error.codeName,\n };\n }\n if (error instanceof Error) {\n return { name: error.name, message: error.message };\n }\n return { name: 'Error', message: String(error) };\n}\n\nfunction cancelledError(): SonareError {\n return new SonareError(ErrorCode.Cancelled, 'Cancelled', 'Operation cancelled');\n}\n\n/**\n * Install the protocol on an endpoint. This export is intentionally useful to\n * the Node `worker_threads` test adapter; browsers install it automatically\n * when this module is loaded as a Worker entry point.\n */\nexport function installOfflineWorkerEndpoint(endpoint: OfflineWorkerEndpoint): void {\n const cancelled = new Set<number>();\n\n const run = async (message: OfflineWorkerRunMessage): Promise<void> => {\n const cancelFlag = message.cancelBuffer ? new Int32Array(message.cancelBuffer) : undefined;\n const isCancelled = (): boolean =>\n cancelled.has(message.id) || (cancelFlag !== undefined && Atomics.load(cancelFlag, 0) !== 0);\n const onProgress = (progress: number, stage: string): undefined | false => {\n endpoint.postMessage({ type: 'sonare:offline-progress', id: message.id, progress, stage });\n return isCancelled() ? false : undefined;\n };\n\n try {\n await init();\n if (isCancelled()) {\n throw cancelledError();\n }\n\n let result: unknown;\n switch (message.operation) {\n case 'analyze':\n result = analyzeWithProgress({\n ...(message.request as unknown as MusicAnalyzeRequest),\n onProgress,\n });\n break;\n case 'detectBpm':\n result = detectBpm(message.request as unknown as SamplesRequest);\n break;\n case 'detectKey':\n result = detectKey(message.request as unknown as DetectKeyRequest);\n break;\n case 'detectChords':\n result = detectChords(message.request as unknown as DetectChordsRequest);\n break;\n case 'masterAudio':\n result = masterAudio({\n ...(message.request as unknown as MasterAudioRequest),\n onProgress,\n });\n break;\n case 'masterAudioStereo':\n result = masterAudioStereo({\n ...(message.request as unknown as MasterAudioStereoRequest),\n onProgress,\n });\n break;\n }\n if (isCancelled()) {\n throw cancelledError();\n }\n endpoint.postMessage(\n { type: 'sonare:offline-result', id: message.id, result },\n transferableBuffers(result),\n );\n } catch (error) {\n endpoint.postMessage({\n type: 'sonare:offline-error',\n id: message.id,\n error: errorMessage(error),\n });\n } finally {\n cancelled.delete(message.id);\n }\n };\n\n endpoint.addEventListener('message', (event) => {\n const message = event.data;\n if (message.type === 'sonare:offline-cancel') {\n cancelled.add(message.id);\n return;\n }\n void run(message);\n });\n}\n\nfunction browserWorkerEndpoint(): OfflineWorkerEndpoint | null {\n const scope = globalThis as unknown as {\n document?: unknown;\n postMessage?: (message: OfflineWorkerResponseMessage, transfer?: Transferable[]) => void;\n addEventListener?: (\n type: 'message',\n listener: (event: MessageEvent<OfflineWorkerRequestMessage>) => void,\n ) => void;\n };\n if (scope.document !== undefined || !scope.postMessage || !scope.addEventListener) {\n return null;\n }\n return {\n postMessage: (message, transfer) => scope.postMessage?.(message, transfer),\n addEventListener: (type, listener) => scope.addEventListener?.(type, listener),\n };\n}\n\nconst endpoint = browserWorkerEndpoint();\nif (endpoint) {\n installOfflineWorkerEndpoint(endpoint);\n}\n"],"mappings":"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","names":["module","requireModule","requireModule","requireModule","endpoint"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/module_state.ts","../src/codes.ts","../src/validation.ts","../src/_chain_config.ts","../src/mastering_chain.ts","../src/public_types_music.ts","../src/analysis_helpers.ts","../src/quick_analysis.ts","../src/index.ts","../src/worker.ts"],"sourcesContent":["/**\n * Numeric error codes carried by a {@link SonareError}. Mirrors the C ABI\n * `SonareError` enum (and the Node / Python surfaces), so the same failure\n * reports the same numeric code on every binding.\n */\nexport enum ErrorCode {\n Ok = 0,\n FileNotFound = 1,\n InvalidFormat = 2,\n DecodeFailed = 3,\n InvalidParameter = 4,\n OutOfMemory = 5,\n NotSupported = 6,\n InvalidState = 7,\n Cancelled = 8,\n EncodeFailed = 9,\n Unknown = 99,\n}\n\n/**\n * Error thrown by libsonare on a native (C++) failure. Carries a numeric\n * {@link ErrorCode} `code` plus its canonical `codeName`, so callers can branch\n * on the cause instead of matching message text.\n *\n * Narrow a caught value with {@link isSonareError} or with `instanceof`; both\n * accept the same values. The Node package exports the same class under the\n * same name.\n */\nexport class SonareError extends Error {\n /** Numeric error code, equal to an {@link ErrorCode} value. */\n readonly code: number;\n /** Canonical name of `code`, e.g. `'InvalidParameter'`. */\n readonly codeName: string;\n\n constructor(code: number, codeName: string, message: string) {\n super(message);\n this.name = 'SonareError';\n this.code = code;\n this.codeName = codeName;\n }\n\n /**\n * Brand-based `instanceof`: an error that carries the shape narrows here even\n * when it is not literally an instance of this class. That is not a\n * hypothetical — an error posted from the analysis worker arrives as a\n * structured clone with its prototype gone, which a prototype-based\n * `instanceof` would silently miss. Delegates to {@link isSonareError} so the\n * two never disagree.\n */\n static [Symbol.hasInstance](value: unknown): value is SonareError {\n return isSonareError(value);\n }\n}\n\n/**\n * Type guard: whether a caught value is a libsonare {@link SonareError}.\n *\n * Duck-typed on purpose: a value that crossed a worker boundary has lost its\n * prototype, so a prototype check would miss it.\n */\nexport function isSonareError(value: unknown): value is SonareError {\n return (\n value instanceof Error &&\n (value as { name?: unknown }).name === 'SonareError' &&\n typeof (value as { code?: unknown }).code === 'number'\n );\n}\n","import { ErrorCode, SonareError } from './errors';\nimport type { SonareModule } from './sonare.js';\n\nlet wrappedModule: SonareModule | null = null;\n\n/**\n * Shape of the structured info the native `sonareExceptionInfo(ptr)` returns.\n */\ninterface NativeExceptionInfo {\n code: number;\n codeName: string;\n message: string;\n}\n\n/**\n * Recover the native exception-object pointer from a value thrown across the\n * WASM boundary. emscripten surfaces a C++ throw in two shapes depending on the\n * toolchain/exception mode:\n * - a raw pointer number (older / classic surfacing), or\n * - a `CppException` object exposing the pointer as `excPtr` (emscripten with\n * `-fexceptions`).\n * Returns null when the thrown value is neither (a genuine JS error), so the\n * caller rethrows it unchanged.\n */\nexport function nativeExceptionPtr(error: unknown): number | null {\n if (typeof error === 'number') {\n return error;\n }\n if (error !== null && typeof error === 'object') {\n const ptr = (error as { excPtr?: unknown }).excPtr;\n if (typeof ptr === 'number') {\n return ptr;\n }\n }\n return null;\n}\n\n/**\n * Turn a thrown native exception pointer into a {@link SonareError}. The bound\n * `sonareExceptionInfo` decodes the pointer back into { code, codeName,\n * message }, then `sonareReleaseException` drops the reference emscripten's\n * `__cxa_throw` took before rethrowing the pointer into JS.\n *\n * The release is mandatory, not an optimization: no C++ frame catches the\n * exception, so that reference is the only one and nothing else ever drops it.\n * Every rejected input would otherwise leak its exception object for the\n * lifetime of the module — and rejection-as-control-flow (re-validating markers\n * or clips on each edit, a scrub handle seeking every pointer move) is a\n * documented usage of this API. It runs in a `finally` so a decode failure\n * still frees, and after decoding because freeing invalidates the message.\n */\nfunction makeSonareError(raw: SonareModule, thrown: number): SonareError {\n let code: number = ErrorCode.Unknown;\n let codeName = 'Unknown';\n let message = `libsonare native exception (${thrown})`;\n try {\n const info = (\n raw as unknown as { sonareExceptionInfo?: (ptr: number) => NativeExceptionInfo }\n ).sonareExceptionInfo?.(thrown);\n if (info) {\n code = info.code ?? code;\n codeName = info.codeName ?? codeName;\n message = info.message || message;\n }\n } catch {\n // Fall back to the generic message if decoding fails.\n } finally {\n try {\n raw.sonareReleaseException(thrown);\n } catch {\n // A module built before the release binding existed still yields an error\n // object; it just keeps leaking, which is what this replaces.\n }\n }\n return new SonareError(code, codeName, message);\n}\n\n/**\n * Wrap the embind module so a native C++ exception (which surfaces as a raw\n * pointer number or a `CppException` carrying one) is rethrown as a\n * {@link SonareError}. Only function-valued\n * members are wrapped, and the wrapper is cached per member so repeated access\n * stays cheap; non-function members (typed-array heap views, etc.) pass through\n * unchanged.\n */\nfunction wrapModuleErrors(raw: SonareModule): SonareModule {\n const cache = new Map<PropertyKey, unknown>();\n const objectCache = new WeakMap<object, unknown>();\n const convert = (error: unknown): never => {\n const ptr = nativeExceptionPtr(error);\n if (ptr !== null) {\n throw makeSonareError(raw, ptr);\n }\n throw error;\n };\n\n const wrapNativeObject = (value: unknown): unknown => {\n if (value === null || typeof value !== 'object') {\n return value;\n }\n if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer || value instanceof Promise) {\n return value;\n }\n // Plain result data carries no native methods, and a Proxy cannot be\n // structured-cloned, so wrapping it would block postMessage to a worker.\n const proto = Object.getPrototypeOf(value);\n if (Array.isArray(value) || proto === Object.prototype || proto === null) {\n return value;\n }\n const objectValue = value as object;\n const cached = objectCache.get(objectValue);\n if (cached) {\n return cached;\n }\n const methodCache = new Map<PropertyKey, unknown>();\n const wrapped = new Proxy(objectValue, {\n get(target, prop, receiver) {\n const member = Reflect.get(target, prop, receiver);\n if (typeof member !== 'function') {\n return member;\n }\n const cachedMethod = methodCache.get(prop);\n if (cachedMethod) {\n return cachedMethod;\n }\n const method = member as (...a: unknown[]) => unknown;\n const wrappedMethod = (...args: unknown[]) => {\n try {\n return wrapNativeObject(Reflect.apply(method, target, args));\n } catch (error) {\n return convert(error);\n }\n };\n methodCache.set(prop, wrappedMethod);\n return wrappedMethod;\n },\n });\n objectCache.set(objectValue, wrapped);\n return wrapped;\n };\n\n const wrapFunction = (value: (...a: unknown[]) => unknown): unknown => {\n const fnCache = new Map<PropertyKey, unknown>();\n return new Proxy(value, {\n get(target, prop, receiver) {\n const member = Reflect.get(target, prop, receiver);\n if (typeof member !== 'function') {\n return member;\n }\n const cachedMember = fnCache.get(prop);\n if (cachedMember) {\n return cachedMember;\n }\n const fn = member as (...a: unknown[]) => unknown;\n const wrappedMember = (...args: unknown[]) => {\n try {\n return wrapNativeObject(Reflect.apply(fn, target, args));\n } catch (error) {\n return convert(error);\n }\n };\n fnCache.set(prop, wrappedMember);\n return wrappedMember;\n },\n apply(t, thisArg, args) {\n try {\n return wrapNativeObject(Reflect.apply(t, thisArg, args as unknown[]));\n } catch (error) {\n return convert(error);\n }\n },\n construct(t, args, newTarget) {\n try {\n return wrapNativeObject(Reflect.construct(t, args as unknown[], newTarget)) as object;\n } catch (error) {\n return convert(error) as object;\n }\n },\n });\n };\n\n return new Proxy(raw, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n if (typeof value !== 'function') {\n return value;\n }\n const cached = cache.get(prop);\n if (cached) {\n return cached;\n }\n // Wrap as a Proxy (not a plain function) so embind class constructors\n // invoked via `new module.Foo(...)` keep their `[[Construct]]` behaviour\n // and prototype while still converting thrown native pointers.\n const wrapped = wrapFunction(value as (...a: unknown[]) => unknown);\n cache.set(prop, wrapped);\n return wrapped;\n },\n }) as SonareModule;\n}\n\nexport function setSonareModule(module: SonareModule): void {\n wrappedModule = wrapModuleErrors(module);\n}\n\nexport function getSonareModule(): SonareModule {\n if (!wrappedModule) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return wrappedModule;\n}\n","import type { ProjectAutomationCurve } from './project_types';\nimport type {\n AutomationCurve,\n MeterTap,\n PanLawInput,\n PanMode,\n SendTiming,\n SidechainSourceKind,\n} from './public_types';\n\n/** Resolve a numeric ordinal in an inclusive range without coercion. */\nexport function resolveOrdinalInRange(\n value: unknown,\n min: number,\n max: number,\n enumName: string,\n): number {\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < min || value > max) {\n throw new RangeError(`Invalid ${enumName}: ${String(value)}`);\n }\n return value;\n}\n\n/** Resolve a public enum spelling or ordinal without permitting unknown values. */\nexport function resolveEnumOrdinal(\n value: unknown,\n values: Readonly<Record<string, number>>,\n enumName: string,\n): number {\n if (typeof value === 'number') {\n const ordinals = Object.values(values);\n const ordinal = resolveOrdinalInRange(\n value,\n Math.min(...ordinals),\n Math.max(...ordinals),\n enumName,\n );\n if (!ordinals.includes(ordinal)) {\n throw new RangeError(`Invalid ${enumName}: ${String(value)}`);\n }\n return ordinal;\n }\n if (typeof value === 'string') {\n const ordinal = values[value];\n if (ordinal !== undefined) {\n return ordinal;\n }\n }\n throw new RangeError(`Invalid ${enumName}: ${String(value)}`);\n}\n\n/**\n * Automation curve spellings and their `SonareAutomationCurve` ordinals.\n *\n * Single source of truth for the vocabulary: {@link AutomationCurve} and\n * {@link ProjectAutomationCurve} are derived from these keys, so a spelling\n * cannot be documented without resolving, or resolve without being documented.\n */\nexport const AUTOMATION_CURVE_VALUES = {\n linear: 0,\n exponential: 1,\n hold: 2,\n 's-curve': 3,\n} as const;\n\n/**\n * The Project facade additionally accepts the legacy `'scurve'` spelling for\n * compatibility with project data written before `'s-curve'` was canonical.\n * The Node package declares the same pair of tables, so a breakpoint accepted\n * by one facade resolves to the same ordinal on the other.\n */\nexport const PROJECT_AUTOMATION_CURVE_VALUES = {\n ...AUTOMATION_CURVE_VALUES,\n scurve: 3,\n} as const;\nconst PAN_LAW_VALUES: Readonly<Record<string, number>> = {\n const3db: 0,\n 'const-3db': 0,\n '-3db': 0,\n 'const4.5db': 1,\n 'const-4.5db': 1,\n '-4.5db': 1,\n const6db: 2,\n 'const-6db': 2,\n '-6db': 2,\n linear0db: 3,\n 'linear-0db': 3,\n linear: 3,\n '0db': 3,\n} as const;\nconst PAN_MODE_VALUES = {\n balance: 0,\n pan: 1,\n stereopan: 1,\n 'stereo-pan': 1,\n dualpan: 2,\n 'dual-pan': 2,\n} as const;\nconst METER_TAP_VALUES = { preFader: 0, postFader: 1 } as const;\nconst SEND_TIMING_VALUES = { postFader: 0, preFader: 1 } as const;\nconst SIDECHAIN_SOURCE_KIND_VALUES = { track: 0, bus: 1 } as const;\nconst TRACK_MONITOR_MODE_VALUES = { off: 0, pfl: 1, afl: 2 } as const;\n\nexport function automationCurveCode(curve: AutomationCurve): number {\n return resolveEnumOrdinal(curve, AUTOMATION_CURVE_VALUES, 'automation curve');\n}\n\n/** Resolve a Project automation breakpoint curve, legacy spellings included. */\nexport function projectAutomationCurveCode(curve: ProjectAutomationCurve | undefined): number {\n return resolveEnumOrdinal(curve ?? 'linear', PROJECT_AUTOMATION_CURVE_VALUES, 'automation curve');\n}\n\nexport function panLawCode(panLaw: PanLawInput): number {\n const normalized = typeof panLaw === 'string' ? panLaw.toLowerCase().replace(/_/g, '-') : panLaw;\n return resolveEnumOrdinal(normalized, PAN_LAW_VALUES, 'pan law');\n}\n\nexport function panModeCode(panMode: PanMode | number): number {\n const normalized =\n typeof panMode === 'string' ? panMode.replace(/_/g, '-').toLowerCase() : panMode;\n return resolveEnumOrdinal(normalized, PAN_MODE_VALUES, 'pan mode');\n}\n\nexport function meterTapCode(tap: MeterTap | number): number {\n return resolveEnumOrdinal(tap, METER_TAP_VALUES, 'meter tap');\n}\n\nexport function sendTimingCode(timing: SendTiming | number): number {\n // Mirrors SonareSendTiming: post-fader is 0 (so an omitted/zeroed value is\n // post-fader), pre-fader is 1. A raw number is passed through as the C ABI int.\n // An unknown string is rejected rather than silently routed to post-fader,\n // matching the sibling enum-code helpers and Node's sendTimingValue.\n return resolveEnumOrdinal(timing, SEND_TIMING_VALUES, 'send timing');\n}\n\n/** Resolve a sidechain source kind to its `SonareSidechainSourceKind` ordinal. */\nexport function sidechainSourceKindCode(kind: SidechainSourceKind | number): number {\n return resolveEnumOrdinal(kind, SIDECHAIN_SOURCE_KIND_VALUES, 'sidechain source kind');\n}\n\n/** Resolve a per-track PFL/AFL monitor mode to its C-ABI ordinal. */\nexport function trackMonitorModeCode(mode: unknown): number {\n return resolveEnumOrdinal(mode, TRACK_MONITOR_MODE_VALUES, 'track monitor mode');\n}\n","import { ErrorCode, SonareError } from './errors';\n\n/**\n * Per-call validation options accepted by guarded wrappers. Empty-buffer\n * checks are always performed; pass `{ validate: false }` to opt out of the\n * O(n) NaN/Inf scan on hot paths.\n *\n * `{ validate: false }` only skips this JS-side pre-scan (which raises a\n * `RangeError` naming the exact offending index). It is NOT a way to push\n * non-finite samples into the core: the native layer always re-validates the\n * buffer — through `validate_offline_audio_input` for the offline-analysis\n * entry points, and through the computation's own per-sample guard where a call\n * takes no sample rate to validate against (the waveform bucket kernels) —\n * matching the C ABI / Node / Python surfaces, so an NaN/Inf buffer still\n * throws, just with a generic native message instead of the indexed JS one.\n */\nexport interface ValidateOptions {\n validate?: boolean;\n}\n\n/**\n * Offline-analysis sample-rate bounds, mirroring the C++ core limits\n * (`sonare::kMinAudioSampleRate` / `kMaxAudioSampleRate` in `core/audio.h`).\n * Every guarded WASM entry point rejects the same out-of-range rates the C ABI,\n * Node, and Python surfaces do.\n */\nexport const MIN_AUDIO_SAMPLE_RATE = 8000;\nexport const MAX_AUDIO_SAMPLE_RATE = 384000;\n\nfunction assertNonEmptySamples(\n fnName: string,\n samples: ArrayLike<number>,\n argName = 'samples',\n): void {\n if (samples.length === 0) {\n throw new RangeError(`${fnName}: ${argName} must not be empty`);\n }\n}\n\nfunction assertFiniteSamples(\n fnName: string,\n samples: ArrayLike<number>,\n validate: boolean,\n argName = 'samples',\n): void {\n if (!validate) {\n return;\n }\n for (let i = 0; i < samples.length; i++) {\n const v = samples[i] as number;\n if (!Number.isFinite(v)) {\n throw new RangeError(`${fnName}: ${argName} contains NaN or Inf at index ${i}`);\n }\n }\n}\n\nexport function assertSamples(\n fnName: string,\n samples: ArrayLike<number>,\n validate: boolean,\n argName = 'samples',\n): void {\n assertNonEmptySamples(fnName, samples, argName);\n assertFiniteSamples(fnName, samples, validate, argName);\n}\n\n/**\n * `assertSamples` restricted to the span a windowed entry point actually reads.\n *\n * The emptiness check still covers the whole buffer, and the reported index is\n * the absolute one, so the message keeps naming the sample the caller passed.\n * What narrows is the scan: a windowed call refuses a non-finite sample inside\n * its frame and is indifferent to one outside it, which is the contract the C\n * ABI states and the cost model it promises -- per call the scan is bounded by\n * the frame, not by the length of the buffer being polled.\n */\nexport function assertSamplesInWindow(\n fnName: string,\n samples: ArrayLike<number>,\n validate: boolean,\n windowStart: number,\n windowLength: number,\n argName = 'samples',\n): void {\n assertNonEmptySamples(fnName, samples, argName);\n if (!validate) {\n return;\n }\n // Floored and ceiled before use: a fractional offset is refused by the layer\n // that owns it, but an index of 100.5 reads `undefined` out of the buffer and\n // would be reported here as a non-finite sample that is not there.\n const start = Math.min(Math.max(Math.floor(windowStart), 0), samples.length);\n const stop = Math.min(start + Math.max(Math.ceil(windowLength), 0), samples.length);\n for (let i = start; i < stop; i++) {\n const v = samples[i] as number;\n if (!Number.isFinite(v)) {\n throw new RangeError(`${fnName}: ${argName} contains NaN or Inf at index ${i}`);\n }\n }\n}\n\nexport function assertFiniteScalar(fnName: string, value: number, argName: string): void {\n if (!Number.isFinite(value)) {\n throw new RangeError(`${fnName}: ${argName} must be a finite number`);\n }\n}\n\n/**\n * A NaN gamma is the automatic-bandwidth sentinel the variable-Q transform\n * documents, alongside a negative value, so only an infinity is out of domain.\n */\nexport function assertVqtGamma(fnName: string, gamma: number): void {\n if (gamma === Number.POSITIVE_INFINITY || gamma === Number.NEGATIVE_INFINITY) {\n throw new RangeError(`${fnName}: gamma must not be infinite`);\n }\n}\n\nexport function assertSampleRate(fnName: string, sampleRate: number, argName = 'sampleRate'): void {\n // Two refusals, not one: 22050.7 sits inside the range, so reporting it as\n // out of range names an argument that is not the one at fault. `argName` is\n // the same point for a rate the caller spelled something else, such as a\n // resampler's source and target.\n if (!Number.isInteger(sampleRate)) {\n throw new RangeError(`${fnName}: ${argName} must be an integer`);\n }\n if (sampleRate < MIN_AUDIO_SAMPLE_RATE || sampleRate > MAX_AUDIO_SAMPLE_RATE) {\n throw new RangeError(\n `${fnName}: ${argName} out of supported range [${MIN_AUDIO_SAMPLE_RATE}, ${MAX_AUDIO_SAMPLE_RATE}]`,\n );\n }\n}\n\n/** Validate and retain the public Audio.fromBuffer construction contract. */\nexport function validateAudioBuffer(samples: Float32Array, sampleRate: number): void {\n assertSamples('Audio.fromBuffer', samples, true);\n assertSampleRate('Audio.fromBuffer', sampleRate);\n}\n\n/** Bounds of the native `int` every embind argument below is narrowed into. */\nexport const C_INT_MIN = -2147483648;\nexport const C_INT_MAX = 2147483647;\n\n/**\n * Reject an argument embind's declared-`int` narrowing would wrap.\n *\n * A positional embind parameter declared `int` WRAPS rather than saturates, so\n * a kernel of `2 ** 32` arrives as 0 and `2 ** 32 + 1` as 1 — both values the\n * native guards accept, so the call succeeds having separated on a setting the\n * caller never asked for. (The options-object path narrows through\n * `checkedIntFromVal`, which refuses the same inputs in the module; this is the\n * positional path's equivalent.)\n *\n * Reported as the branded `SonareError` carrying `InvalidParameter` rather than\n * a `RangeError`, because the class follows what the rejection stands in for: a\n * `RangeError` is this surface refusing an argument on its own authority, while\n * this one pre-empts a native refusal the caller would have received under that\n * code had the narrowing not wrapped the value into the accepted domain first.\n * The agreement with the Node and Python surfaces is asserted by the Node\n * package's `tests/narrowing-code-parity.test.ts`, which drives one value\n * through all three — weakening this check turns that red.\n */\nexport function assertInt32(fnName: string, value: number, argName: string): void {\n if (!Number.isInteger(value) || value < C_INT_MIN || value > C_INT_MAX) {\n throw new SonareError(\n ErrorCode.InvalidParameter,\n 'InvalidParameter',\n `${fnName}: ${argName} must be an integer within the signed 32-bit range`,\n );\n }\n}\n\n/**\n * Check both HPSS kernels before embind narrows them.\n *\n * Parity, positivity and the ceiling stay the core's to enforce, and it names\n * the median filter that rejected the value. What cannot be deferred is the\n * narrowing itself: a wrapped kernel arrives as a legal one and separates on it.\n *\n * These two arrive POSITIONALLY, so they never pass through the options-bag\n * reader and inherit none of its checks. That is what separates this from\n * {@link assertPercussiveSeparation}, which duplicates a reader check to improve\n * a message; here there is no reader to duplicate.\n */\nexport function assertHpssKernels(\n fnName: string,\n kernelHarmonic: number,\n kernelPercussive: number,\n): void {\n assertInt32(fnName, kernelHarmonic, 'kernelHarmonic');\n assertInt32(fnName, kernelPercussive, 'kernelPercussive');\n}\n\nfunction assertIntegralField(fnName: string, value: number, argName: string): void {\n if (!Number.isInteger(value)) {\n throw new SonareError(\n ErrorCode.InvalidParameter,\n 'InvalidParameter',\n `${fnName}: ${argName} must be an integer`,\n );\n }\n}\n\n/**\n * Percussive-event separation fields, as the request objects carry them.\n */\nexport interface PercussiveSeparationFields {\n nFft?: number;\n hopLength?: number;\n hpssKernelHarmonic?: number;\n hpssKernelPercussive?: number;\n}\n\n/**\n * Check the percussive-event separation's framing and kernels for integrality.\n *\n * All four fields reach the module through one options-bag reader, which now\n * refuses a fractional value itself, so this is the diagnostic rather than the\n * guarantee: it fires first and names the function, where the reader can only\n * name the field. Both reject the same set, so they cannot disagree about an\n * input — only about how the message reads. Do not narrow this to fields the\n * reader misses; there are none, and a check scoped to a gap that no longer\n * exists is how a stale justification outlives its divergence.\n *\n * The fields are iterated rather than named at each call site so a new one is\n * visible here. Absence means the default, so an omitted field is not resolved.\n */\nexport function assertPercussiveSeparation(\n fnName: string,\n options: PercussiveSeparationFields,\n): void {\n const fields = ['nFft', 'hopLength', 'hpssKernelHarmonic', 'hpssKernelPercussive'] as const;\n for (const field of fields) {\n const value = options[field];\n if (value !== undefined) {\n assertIntegralField(fnName, value, field);\n }\n }\n}\n\nexport function assertNonNegativeInteger(fnName: string, value: number, argName: string): void {\n if (!Number.isInteger(value) || value < 0) {\n throw new RangeError(`${fnName}: ${argName} must be a non-negative integer`);\n }\n}\n\n/** Integer strictly greater than zero, up to the native `int` ceiling. */\nexport function assertPositiveInteger(fnName: string, value: number, argName: string): void {\n // Two refusals, not one: 512.7 is positive, so reporting it as non-positive\n // names a property it has. The ceiling travels with the sign rather than with\n // integrality, because both describe a value the native `int` can carry.\n if (!Number.isInteger(value)) {\n throw new RangeError(`${fnName}: ${argName} must be an integer`);\n }\n if (value <= 0 || value > C_INT_MAX) {\n throw new RangeError(`${fnName}: ${argName} must be a positive integer`);\n }\n}\n\n/**\n * Split \"not an integer\" into the two mistakes it can be: `TypeError` when the\n * value is not a `number` at all, `RangeError` when it is a number but not\n * integral -- the right-type, wrong-domain half of the same message.\n *\n * `Number.isInteger` alone answers both, which is why a single check reads as\n * sufficient; what it cannot do is say which one happened, and a caller can act\n * only on the mistake they made. The classes are the contract on this surface,\n * so a sibling argument in the same call must not report a fraction differently\n * from this one.\n */\nexport function assertIntegerValue(\n fnName: string,\n value: unknown,\n argName: string,\n): asserts value is number {\n if (typeof value !== 'number') {\n throw new TypeError(`${fnName}: ${argName} must be an integer`);\n }\n if (!Number.isInteger(value)) {\n throw new RangeError(`${fnName}: ${argName} must be an integer`);\n }\n}\n\n/** Even integer in `[min, max]`, for an FFT-style size where only parity matters. */\nexport function assertEvenIntegerAtLeast(\n fnName: string,\n value: number,\n argName: string,\n min: number,\n max: number,\n): void {\n // Range and parity are separate refusals: 2 ** 31 is already even, so telling\n // its caller the value must be even names a property it has.\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new RangeError(`${fnName}: ${argName} must be an integer in [${min}, ${max}]`);\n }\n if (value % 2 !== 0) {\n throw new RangeError(`${fnName}: ${argName} must be an even integer`);\n }\n}\n\n/** General integer-in-`[min, max]` check, for a bound {@link assertU7}/{@link assertNibble} don't cover. */\nexport function assertBoundedInteger(\n fnName: string,\n value: number,\n argName: string,\n min: number,\n max: number,\n): void {\n if (!Number.isInteger(value) || value < min || value > max) {\n throw new RangeError(`${fnName}: ${argName} must be an integer in [${min}, ${max}]`);\n }\n}\n\nexport function assertU7(fnName: string, value: number, argName: string): number {\n if (!Number.isInteger(value) || value < 0 || value > 127) {\n throw new RangeError(`${fnName}: ${argName} must be an integer in [0, 127]`);\n }\n return value;\n}\n\nexport function assertNibble(fnName: string, value: number, argName: string): number {\n if (!Number.isInteger(value) || value < 0 || value > 15) {\n throw new RangeError(`${fnName}: ${argName} must be an integer in [0, 15]`);\n }\n return value;\n}\n\nexport function assertU32(fnName: string, value: number, argName: string): void {\n if (!Number.isInteger(value) || value < 0 || value > 0xffffffff) {\n throw new RangeError(`${fnName}: ${argName} must be an integer in [0, 4294967295]`);\n }\n}\n\n/**\n * Convert a caller-supplied index array to `Int32Array`, refusing any element\n * the conversion would change rather than folding it.\n *\n * `Int32Array.from(values, Math.trunc)` turns the sample index `1000.7` into\n * `1000` and `2 ** 31` into `-2 ** 31`. The C ABI takes `const int*`, so both\n * arrive as values nothing downstream can separate from ones the caller chose.\n * An `Int32Array` is returned as-is: its elements are already exact.\n */\nexport function toInt32Array(\n fnName: string,\n values: Int32Array | ArrayLike<number>,\n argName: string,\n): Int32Array {\n if (values instanceof Int32Array) {\n return values;\n }\n const out = new Int32Array(values.length);\n for (let i = 0; i < values.length; i++) {\n const element = values[i];\n // The element shape of `assertIntegerValue`, and it splits the same way: the\n // class says whether the entry was the wrong type or the wrong domain, and a\n // sibling element in the same array must not report a fraction differently.\n if (typeof element !== 'number') {\n throw new TypeError(`${fnName}: ${argName}[${i}] must be an integer`);\n }\n if (!Number.isInteger(element)) {\n throw new RangeError(`${fnName}: ${argName}[${i}] must be an integer`);\n }\n if (element < C_INT_MIN || element > C_INT_MAX) {\n throw new RangeError(\n `${fnName}: ${argName}[${i}] must be an integer in [${C_INT_MIN}, ${C_INT_MAX}]`,\n );\n }\n out[i] = element;\n }\n return out;\n}\n\nexport function assertInterleavedSamples(\n fnName: string,\n samples: ArrayLike<number>,\n channels: number,\n validate: boolean,\n): void {\n assertSamples(fnName, samples, validate);\n assertPositiveInteger(fnName, channels, 'channels');\n if (samples.length % channels !== 0) {\n throw new RangeError(`${fnName}: samples length must be a multiple of channels`);\n }\n}\n","import type { MasteringChainConfig } from './public_types';\n\ntype ChainSection = { [key: string]: number | boolean | ChainSection | undefined };\n\n/**\n * Flattens a nested {@link MasteringChainConfig} into the dot-notation\n * `{ \"module.processor.param\": value }` map the core consumes. Internal helper\n * shared by the mastering-chain / master-audio entry points. The core owns\n * legacy leaf-name aliases, so this remains a structural flattening step.\n *\n * A key the caller already wrote in dot notation carries through untouched, so\n * both spellings a {@link MasteringChainConfig} accepts reach the core as the\n * same parameter — matching what the Python binding documents. An unknown key\n * in either spelling is rejected by the core, not here.\n */\nexport function flattenChainConfig(config: MasteringChainConfig): Record<string, number | boolean> {\n const out: Record<string, number | boolean> = {};\n const walk = (node: ChainSection, prefix: string): void => {\n for (const [key, value] of Object.entries(node)) {\n const path = prefix ? `${prefix}.${key}` : key;\n if (typeof value === 'number' || typeof value === 'boolean') {\n out[path] = value;\n } else if (value !== null && typeof value === 'object') {\n walk(value, path);\n } else if (value !== undefined) {\n throw new TypeError(`Mastering override '${path}' must be a number or boolean.`);\n }\n }\n };\n walk(config as ChainSection, '');\n\n return out;\n}\n","import { flattenChainConfig } from './_chain_config';\nimport { getSonareModule } from './module_state';\nimport type {\n MasteringChainConfig,\n MasteringChainResult,\n MasteringChainStereoResult,\n MasteringPreset,\n} from './public_types';\nimport type { ProgressCallback } from './sonare.js';\nimport type { ValidateOptions } from './validation';\nimport { assertSamples } from './validation';\n\nfunction requireModule() {\n return getSonareModule();\n}\n\nexport type NormalizeMode = 'peak' | 'rms';\n\n// `context` is the calling entry point's name: the refusal is about that\n// caller's argument, so naming a fixed one would send a normalizeStereo user\n// looking at normalize.\nfunction resolveNormalizeMode(value: unknown, context = 'normalize'): NormalizeMode {\n if (value === undefined) {\n return 'peak';\n }\n if (typeof value !== 'string') {\n throw new TypeError(`${context}: mode must be the string 'peak' or 'rms'`);\n }\n if (value !== 'peak' && value !== 'rms') {\n throw new RangeError(`${context}: mode must be the string 'peak' or 'rms'`);\n }\n return value;\n}\n\nexport interface NormalizeRequest extends ValidateOptions {\n samples: Float32Array;\n sampleRate?: number;\n targetDb?: number;\n mode?: NormalizeMode;\n}\n\n/**\n * Normalize audio to a target peak or RMS level.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param targetDb - Finite target at or below 0 dBFS (default: 0 dB = full scale).\n * For `mode: 'peak'`, this is the peak target; for `mode: 'rms'`, this is the RMS target.\n * @param mode - Normalization mode: `'peak'` (default) or `'rms'`.\n * @returns Normalized audio\n */\nexport function normalize(request: NormalizeRequest): Float32Array;\nexport function normalize(\n samples: Float32Array,\n sampleRate: number,\n targetDb?: number,\n options?: ValidateOptions,\n): Float32Array;\nexport function normalize(\n samples: Float32Array,\n sampleRate: number,\n targetDb?: number,\n mode?: NormalizeMode,\n options?: ValidateOptions,\n): Float32Array;\nexport function normalize(\n samples: Float32Array | NormalizeRequest,\n sampleRate?: number,\n targetDb = 0.0,\n modeOrOptions: NormalizeMode | ValidateOptions = 'peak',\n options: ValidateOptions = {},\n): Float32Array {\n if (\n modeOrOptions !== undefined &&\n modeOrOptions !== null &&\n typeof modeOrOptions !== 'string' &&\n typeof modeOrOptions !== 'object'\n ) {\n throw new TypeError(\"normalize: mode must be the string 'peak' or 'rms'\");\n }\n if (modeOrOptions === null) {\n throw new TypeError(\"normalize: mode must be the string 'peak' or 'rms'\");\n }\n const positionalOptions =\n typeof modeOrOptions === 'object' && modeOrOptions !== null ? modeOrOptions : options;\n const positionalMode = typeof modeOrOptions === 'string' ? modeOrOptions : undefined;\n const request: NormalizeRequest =\n samples instanceof Float32Array\n ? { samples, sampleRate, targetDb, mode: positionalMode, ...positionalOptions }\n : samples;\n assertSamples('normalize', request.samples, request.validate !== false);\n const mode = resolveNormalizeMode(request.mode);\n return requireModule().normalizeEx(\n request.samples,\n request.sampleRate ?? 22050,\n request.targetDb ?? 0.0,\n mode,\n );\n}\n\nexport interface NormalizeStereoRequest extends ValidateOptions {\n left: Float32Array;\n right: Float32Array;\n sampleRate?: number;\n targetDb?: number;\n mode?: NormalizeMode;\n}\n\n/** A normalized channel pair and the gain both channels were moved by. */\nexport interface NormalizeStereoResult {\n left: Float32Array;\n right: Float32Array;\n /**\n * One figure rather than a pair: the gain is one decision shared by both\n * channels. Silence leaves the pair untouched and reports 0.\n */\n appliedGainDb: number;\n}\n\n/**\n * Normalize a stereo pair on a gain measured across both channels.\n *\n * Normalizing the two channels separately lifts the quieter one until the peaks\n * match, which changes the balance rather than the level. The level here is read\n * from the pair and the resulting gain goes to both channels, so the image is\n * preserved: for `mode: 'peak'` the louder channel reaches `targetDb` and the\n * other keeps its distance from it; for `mode: 'rms'` the quantity driven to\n * `targetDb` is the root mean square over both channels' samples together — the\n * quadratic mean of the per-channel figures, not their average — and the output\n * is hard-clipped to [-1, 1].\n *\n * @param request.left - Left channel samples (float32)\n * @param request.right - Right channel samples, same length as `left`\n * @param request.sampleRate - Sample rate in Hz (default: 22050)\n * @param request.targetDb - Finite target at or below 0 dBFS. Defaults to 0 for\n * `mode: 'peak'` and -20 for `mode: 'rms'`, matching the library and the other\n * language surfaces.\n * @param request.mode - `'peak'` (default) or `'rms'`\n * @returns The normalized pair and the shared gain in dB\n * @throws RangeError when the two channels differ in length\n *\n * @example\n * ```ts\n * const { left, right, appliedGainDb } = normalizeStereo({\n * left: leftSamples,\n * right: rightSamples,\n * sampleRate: 44100,\n * targetDb: -1,\n * });\n * ```\n */\nexport function normalizeStereo(request: NormalizeStereoRequest): NormalizeStereoResult {\n assertSamples('normalizeStereo', request.left, request.validate !== false);\n assertSamples('normalizeStereo', request.right, request.validate !== false);\n if (request.left.length !== request.right.length) {\n throw new RangeError('Stereo channel lengths must match.');\n }\n const mode = resolveNormalizeMode(request.mode, 'normalizeStereo');\n // Mode-dependent, unlike the mono `normalize` on this surface, which defaults\n // to 0 dB in both modes. 0 dBFS RMS is not a usable default -- the peaks sit\n // well above the RMS, so every one of them clips -- and the library and the\n // other surfaces all default RMS to -20. A new entry point takes the shared\n // default rather than inheriting a surface-local one.\n const targetDb = request.targetDb ?? (mode === 'rms' ? -20.0 : 0.0);\n return requireModule().normalizeStereo(\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n targetDb,\n mode,\n );\n}\n\n/** Internal envelope selecting the core dotted-param parser in the embind layer. */\nfunction canonicalChainConfig(config: MasteringChainConfig): Record<string, unknown> {\n return { __flatParams: flattenChainConfig(config) };\n}\n\nexport interface MasteringChainRequest {\n samples: Float32Array;\n sampleRate?: number;\n config?: MasteringChainConfig;\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n}\n\nexport interface MasteringChainStereoRequest {\n left: Float32Array;\n right: Float32Array;\n sampleRate?: number;\n config?: MasteringChainConfig;\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n}\n\n/** Canonical request form for one-shot preset mastering. */\nexport interface MasterAudioRequest {\n samples: Float32Array;\n sampleRate?: number;\n preset?: MasteringPreset;\n overrides?: MasteringChainConfig;\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n}\n\n/** Canonical request form for one-shot stereo preset mastering. */\nexport interface MasterAudioStereoRequest {\n left: Float32Array;\n right: Float32Array;\n sampleRate?: number;\n preset?: MasteringPreset;\n overrides?: MasteringChainConfig;\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n}\n\nfunction masterAudioRequest(\n requestOrSamples: MasterAudioRequest | Float32Array,\n sampleRate: number,\n preset: MasteringPreset,\n overrides: MasteringChainConfig | null,\n onProgress?: ProgressCallback,\n): MasterAudioRequest {\n if (requestOrSamples instanceof Float32Array) {\n return {\n samples: requestOrSamples,\n sampleRate,\n preset,\n overrides: overrides ?? {},\n onProgress,\n };\n }\n return requestOrSamples;\n}\n\nfunction masterAudioStereoRequest(\n requestOrLeft: MasterAudioStereoRequest | Float32Array,\n right: Float32Array | undefined,\n sampleRate: number,\n preset: MasteringPreset,\n overrides: MasteringChainConfig | null,\n onProgress?: ProgressCallback,\n): MasterAudioStereoRequest {\n if (requestOrLeft instanceof Float32Array) {\n return {\n left: requestOrLeft,\n right: right as Float32Array,\n sampleRate,\n preset,\n overrides: overrides ?? {},\n onProgress,\n };\n }\n return requestOrLeft;\n}\n\n/**\n * Apply a configurable mastering chain in WASM.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param config - Chain stage configuration\n * @returns Processed audio, loudness metadata, and applied stage names\n */\nexport function masteringChain(request: MasteringChainRequest): MasteringChainResult;\nexport function masteringChain(\n samples: Float32Array,\n sampleRate?: number,\n config?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainResult;\nexport function masteringChain(\n samples: Float32Array | MasteringChainRequest,\n sampleRate = 22050,\n config: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainResult {\n const request =\n samples instanceof Float32Array ? { samples, sampleRate, config, onProgress } : samples;\n if (request.onProgress || request.cancel) {\n return requireModule().masteringChainWithProgress(\n request.samples,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n }\n return requireModule().masteringChain(\n request.samples,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n );\n}\n\n/**\n * Apply a configurable stereo mastering chain in WASM.\n *\n * @param left - Left channel samples\n * @param right - Right channel samples\n * @param sampleRate - Sample rate in Hz\n * @param config - Chain stage configuration\n * @returns Processed stereo audio, loudness metadata, and applied stage names\n */\nexport function masteringChainStereo(\n request: MasteringChainStereoRequest,\n): MasteringChainStereoResult;\nexport function masteringChainStereo(\n left: Float32Array,\n right: Float32Array,\n sampleRate?: number,\n config?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult;\nexport function masteringChainStereo(\n left: Float32Array | MasteringChainStereoRequest,\n right?: Float32Array,\n sampleRate = 22050,\n config: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult {\n const request =\n left instanceof Float32Array\n ? { left, right: right as Float32Array, sampleRate, config, onProgress }\n : left;\n if (request.left.length !== request.right.length) {\n throw new Error('Stereo channel lengths must match.');\n }\n if (request.onProgress || request.cancel) {\n return requireModule().masteringChainStereoWithProgress(\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n }\n return requireModule().masteringChainStereo(\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n );\n}\n\n/**\n * Apply a configurable mastering chain in WASM with progress reporting.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param config - Chain stage configuration\n * @param onProgress - Progress callback (progress: 0-1, stage: string)\n * @returns Processed audio, loudness metadata, and applied stage names\n */\nexport function masteringChainWithProgress(\n request: MasteringChainRequest & Required<Pick<MasteringChainRequest, 'onProgress'>>,\n): MasteringChainResult;\nexport function masteringChainWithProgress(\n samples: Float32Array,\n sampleRate?: number,\n config?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainResult;\nexport function masteringChainWithProgress(\n samples: Float32Array | MasteringChainRequest,\n sampleRate = 22050,\n config: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainResult {\n const request =\n samples instanceof Float32Array ? { samples, sampleRate, config, onProgress } : samples;\n if (!request.onProgress) {\n throw new TypeError('masteringChainWithProgress: onProgress is required');\n }\n return requireModule().masteringChainWithProgress(\n request.samples,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n request.onProgress,\n request.cancel ?? (() => false),\n );\n}\n\n/**\n * Apply a configurable stereo mastering chain in WASM with progress reporting.\n *\n * @param left - Left channel samples\n * @param right - Right channel samples\n * @param sampleRate - Sample rate in Hz\n * @param config - Chain stage configuration\n * @param onProgress - Progress callback (progress: 0-1, stage: string)\n * @returns Processed stereo audio, loudness metadata, and applied stage names\n */\nexport function masteringChainStereoWithProgress(\n request: MasteringChainStereoRequest & Required<Pick<MasteringChainStereoRequest, 'onProgress'>>,\n): MasteringChainStereoResult;\nexport function masteringChainStereoWithProgress(\n left: Float32Array,\n right: Float32Array,\n sampleRate?: number,\n config?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult;\nexport function masteringChainStereoWithProgress(\n left: Float32Array | MasteringChainStereoRequest,\n right?: Float32Array,\n sampleRate = 22050,\n config: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult {\n const request =\n left instanceof Float32Array\n ? { left, right: right as Float32Array, sampleRate, config, onProgress }\n : left;\n if (!request.onProgress) {\n throw new TypeError('masteringChainStereoWithProgress: onProgress is required');\n }\n if (request.left.length !== request.right.length) {\n throw new Error('Stereo channel lengths must match.');\n }\n return requireModule().masteringChainStereoWithProgress(\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n canonicalChainConfig(request.config ?? {}),\n request.onProgress,\n request.cancel ?? (() => false),\n );\n}\n\n/**\n * List built-in mastering preset identifiers.\n *\n * @returns Preset names in display order (e.g. \"pop\", \"edm\", \"aiMusic\")\n */\nexport function masteringPresetNames(): MasteringPreset[] {\n return Array.from(requireModule().masteringPresetNames()) as MasteringPreset[];\n}\n\n/**\n * The flat `{key: number|boolean}` params of preset `preset`'s built-in chain\n * configuration, in the same key space {@link masteringAssistantSuggestChain}\n * returns. Passing this straight through as `overrides` to {@link masterAudio}\n * reproduces the preset unchanged, bit for bit in the C++ core.\n *\n * @param preset - Preset identifier from {@link masteringPresetNames}.\n * @throws For an unknown `preset`.\n */\nexport function masteringPresetParams(preset: MasteringPreset): Record<string, number | boolean> {\n return requireModule().masteringPresetParams(preset);\n}\n\n/**\n * List the delivery targets the mastering assistant accepts as `targetPlatform`.\n *\n * Read from the library rather than from a list kept here, so a target added in\n * the core is discoverable without a binding change.\n *\n * @returns Target names in index order (e.g. \"streaming\", \"broadcast\", \"club\")\n */\nexport function masteringPlatformNames(): string[] {\n return Array.from(requireModule().masteringPlatformNames());\n}\n\n/**\n * Apply a named mastering preset chain to mono audio.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param presetName - Preset identifier from {@link masteringPresetNames}\n * @param overrides - Optional nested {@link MasteringChainConfig} applied on top of the preset (e.g. `{ loudness: { targetLufs: -14 } }`). Pass `null` for preset defaults.\n * @param onProgress - Optional per-stage progress callback (progress: 0-1, stage: string).\n * @returns Processed audio, loudness metadata, and applied stage names\n */\nexport function masterAudio(request: MasterAudioRequest): MasteringChainResult;\nexport function masterAudio(\n samples: Float32Array,\n sampleRate?: number,\n presetName?: MasteringPreset,\n overrides?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainResult;\nexport function masterAudio(\n samples: MasterAudioRequest | Float32Array,\n sampleRate = 22050,\n presetName: MasteringPreset = 'pop',\n overrides: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainResult {\n const request = masterAudioRequest(samples, sampleRate, presetName, overrides, onProgress);\n const flat = flattenChainConfig(request.overrides ?? {});\n if (request.onProgress || request.cancel) {\n return requireModule().masterAudioWithProgress(\n request.preset ?? 'pop',\n request.samples,\n request.sampleRate ?? 22050,\n flat,\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n }\n return requireModule().masterAudio(\n request.preset ?? 'pop',\n request.samples,\n request.sampleRate ?? 22050,\n flat,\n );\n}\n\n/**\n * Apply a named mastering preset chain to stereo audio.\n *\n * @param left - Left channel samples\n * @param right - Right channel samples\n * @param sampleRate - Sample rate in Hz\n * @param presetName - Preset identifier from {@link masteringPresetNames}\n * @param overrides - Optional nested {@link MasteringChainConfig} applied on top of the preset (e.g. `{ loudness: { targetLufs: -14 } }`). Pass `null` for preset defaults.\n * @param onProgress - Optional per-stage progress callback (progress: 0-1, stage: string).\n * @returns Processed stereo audio, loudness metadata, and applied stage names\n */\nexport function masterAudioStereo(request: MasterAudioStereoRequest): MasteringChainStereoResult;\nexport function masterAudioStereo(\n left: Float32Array,\n right: Float32Array,\n sampleRate?: number,\n presetName?: MasteringPreset,\n overrides?: MasteringChainConfig,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult;\nexport function masterAudioStereo(\n left: MasterAudioStereoRequest | Float32Array,\n right: Float32Array | undefined = undefined,\n sampleRate = 22050,\n presetName: MasteringPreset = 'pop',\n overrides: MasteringChainConfig = {},\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult {\n const request = masterAudioStereoRequest(\n left,\n right,\n sampleRate,\n presetName,\n overrides,\n onProgress,\n );\n const flat = flattenChainConfig(request.overrides ?? {});\n if (request.left.length !== request.right.length) {\n throw new Error('Stereo channel lengths must match.');\n }\n if (request.onProgress || request.cancel) {\n return requireModule().masterAudioStereoWithProgress(\n request.preset ?? 'pop',\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n flat,\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n }\n return requireModule().masterAudioStereo(\n request.preset ?? 'pop',\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n flat,\n );\n}\n\n/**\n * Mono `masterAudio` with per-stage progress reporting. `onProgress` is invoked\n * with `(progress, stage)` between each chain stage (progress is in [0,1]).\n */\nexport function masterAudioWithProgress(\n request: MasterAudioRequest & Required<Pick<MasterAudioRequest, 'onProgress'>>,\n): MasteringChainResult;\nexport function masterAudioWithProgress(\n samples: Float32Array,\n sampleRate?: number,\n presetName?: MasteringPreset,\n overrides?: MasteringChainConfig | null,\n onProgress?: ProgressCallback,\n): MasteringChainResult;\nexport function masterAudioWithProgress(\n samples: MasterAudioRequest | Float32Array,\n sampleRate = 22050,\n presetName: MasteringPreset = 'pop',\n overrides: MasteringChainConfig | null = null,\n onProgress?: ProgressCallback,\n): MasteringChainResult {\n const request = masterAudioRequest(samples, sampleRate, presetName, overrides, onProgress);\n if (!request.onProgress) {\n throw new TypeError('masterAudioWithProgress: onProgress is required');\n }\n return requireModule().masterAudioWithProgress(\n request.preset ?? 'pop',\n request.samples,\n request.sampleRate ?? 22050,\n flattenChainConfig(request.overrides ?? {}),\n request.onProgress,\n request.cancel ?? (() => false),\n );\n}\n\n/**\n * Stereo `masterAudio` with per-stage progress reporting.\n */\nexport function masterAudioStereoWithProgress(\n request: MasterAudioStereoRequest & Required<Pick<MasterAudioStereoRequest, 'onProgress'>>,\n): MasteringChainStereoResult;\nexport function masterAudioStereoWithProgress(\n left: Float32Array,\n right: Float32Array,\n sampleRate?: number,\n presetName?: MasteringPreset,\n overrides?: MasteringChainConfig | null,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult;\nexport function masterAudioStereoWithProgress(\n left: MasterAudioStereoRequest | Float32Array,\n right: Float32Array | undefined = undefined,\n sampleRate = 22050,\n presetName: MasteringPreset = 'pop',\n overrides: MasteringChainConfig | null = null,\n onProgress?: ProgressCallback,\n): MasteringChainStereoResult {\n const request = masterAudioStereoRequest(\n left,\n right,\n sampleRate,\n presetName,\n overrides,\n onProgress,\n );\n if (!request.onProgress) {\n throw new TypeError('masterAudioStereoWithProgress: onProgress is required');\n }\n if (request.left.length !== request.right.length) {\n throw new Error('Stereo channel lengths must match.');\n }\n return requireModule().masterAudioStereoWithProgress(\n request.preset ?? 'pop',\n request.left,\n request.right,\n request.sampleRate ?? 22050,\n flattenChainConfig(request.overrides ?? {}),\n request.onProgress,\n request.cancel ?? (() => false),\n );\n}\n","import type { ValidateOptions } from './validation';\n\n/**\n * Pitch class enum (C=0, C#=1, ..., B=11)\n */\nexport const PitchClass = {\n C: 0,\n Cs: 1,\n D: 2,\n Ds: 3,\n E: 4,\n F: 5,\n Fs: 6,\n G: 7,\n Gs: 8,\n A: 9,\n As: 10,\n B: 11,\n} as const;\n\nexport type PitchClass = (typeof PitchClass)[keyof typeof PitchClass];\n\n/**\n * Musical mode\n */\nexport const Mode = {\n Major: 0,\n Minor: 1,\n Dorian: 2,\n Phrygian: 3,\n Lydian: 4,\n Mixolydian: 5,\n Locrian: 6,\n} as const;\n\nexport type Mode = (typeof Mode)[keyof typeof Mode];\n\nexport type TempogramMode = 'autocorrelation' | 'auto' | 'ac' | 'cosine' | 0 | 1;\n\nexport const KeyProfile = {\n KrumhanslSchmuckler: 0,\n Temperley: 1,\n Shaath: 2,\n FaraldoEDMT: 3,\n FaraldoEDMA: 4,\n FaraldoEDMM: 5,\n BellmanBudge: 6,\n} as const;\n\nexport type KeyProfile = (typeof KeyProfile)[keyof typeof KeyProfile];\n\nexport type KeyProfileName =\n | 'ks'\n | 'krumhansl'\n | 'temperley'\n | 'shaath'\n | 'keyfinder'\n | 'faraldo-edmt'\n | 'edmt'\n | 'faraldo-edma'\n | 'edma'\n | 'faraldo-edmm'\n | 'edmm'\n | 'bellman-budge'\n | 'bellman';\n\n/**\n * Chord quality\n */\nexport const ChordQuality = {\n Major: 0,\n Minor: 1,\n Diminished: 2,\n Augmented: 3,\n Dominant7: 4,\n Major7: 5,\n Minor7: 6,\n Sus2: 7,\n Sus4: 8,\n Unknown: 9,\n Add9: 10,\n MinorAdd9: 11,\n Dim7: 12,\n HalfDim7: 13,\n Major9: 14,\n Dominant9: 15,\n Sus2Add4: 16,\n Major6: 17,\n Minor6: 18,\n MinorMajor7: 19,\n Dominant7Sus4: 20,\n Dominant11: 21,\n Dominant13: 22,\n Dominant7Flat9: 23,\n Dominant7Sharp9: 24,\n} as const;\n\nexport type ChordQuality = (typeof ChordQuality)[keyof typeof ChordQuality];\n\n/**\n * Section type.\n *\n * `PreChorus` is never produced by `analyze()`: it has no detection branch, so\n * filtering sections on it always yields an empty result. Every other value is\n * reachable. `Unknown` means the analyzer did not name the segment: no\n * boundary was detected, the segment matched none of the positive branches, or\n * the evidence for a musical function was too weak to assert one. The first\n * case comes with `confidence` 0; the last keeps the sub-threshold score, so a\n * caller can see how close the segment came to a label.\n */\nexport const SectionType = {\n Intro: 0,\n Verse: 1,\n PreChorus: 2,\n Chorus: 3,\n Bridge: 4,\n Instrumental: 5,\n Outro: 6,\n Unknown: 7,\n} as const;\n\nexport type SectionType = (typeof SectionType)[keyof typeof SectionType];\n\n/**\n * Detected musical key\n */\nexport interface Key {\n root: PitchClass;\n mode: Mode;\n /**\n * Share of the model's belief that this key is the answer, in `[0, 1)`.\n *\n * A softmax over the profile correlations of every candidate that was scored,\n * so it falls as the runner-up closes in and two keys that split the evidence\n * -- a relative major and minor, typically -- each report about half.\n *\n * This is the model's own belief, **not** a measured accuracy. It says how\n * decisively the chroma picked this key out of the candidate set; it does not\n * say how often that pick is right, and nothing here has been fitted against\n * annotated recordings. A confident wrong answer is entirely possible, so a\n * pipeline that branches on it must choose its own threshold against its own\n * material.\n */\n confidence: number;\n name: string;\n shortName: string;\n}\n\nexport interface KeyDetectionOptions extends ValidateOptions {\n nFft?: number;\n hopLength?: number;\n useHpss?: boolean;\n loudnessWeighted?: boolean;\n highPassHz?: number;\n modes?:\n | Mode[]\n | ('major' | 'minor' | 'dorian' | 'phrygian' | 'lydian' | 'mixolydian' | 'locrian')[]\n | 'major-minor'\n | 'all'\n | 'modal';\n profile?: KeyProfile | KeyProfileName;\n genreHint?: 'auto' | 'edm' | 'electronic' | 'dance' | 'pop' | 'classical' | 'jazz' | string;\n}\n\nexport interface KeyCandidate {\n key: Key;\n correlation: number;\n}\n\nexport interface ChordDetectionOptions extends ValidateOptions {\n minDuration?: number;\n smoothingWindow?: number;\n /** Final-template correlation threshold in [0, 1]; below it emits Unknown / N.C. */\n threshold?: number;\n useTriadsOnly?: boolean;\n /** STFT chroma window in samples at 22050 Hz, rescaled to the input rate so its duration is the same at every rate. */\n nFft?: number;\n hopLength?: number;\n useBeatSync?: boolean;\n useHmm?: boolean;\n hmmBeamWidth?: number;\n useKeyContext?: boolean;\n keyRoot?: PitchClass;\n keyMode?: Mode;\n detectInversions?: boolean;\n chromaMethod?: 'stft' | 'nnls';\n /**\n * Tuning offset of the recording in fractions of a semitone, the unit\n * `estimateTuning` returns; must be in `[-0.5, 0.5)`. Default 0 (concert A440).\n */\n tuning?: number;\n}\n\n/** Options for `analyzeBpm`. All fields are optional. */\nexport interface AnalyzeBpmOptions extends ValidateOptions {\n /** Lowest BPM to consider. Default 30. */\n bpmMin?: number;\n /** Highest BPM to consider. Default 300. */\n bpmMax?: number;\n /** Tempo prior the tracker is biased toward. Default 120. */\n startBpm?: number;\n /** FFT size for the onset envelope. Default 2048. */\n nFft?: number;\n /** Hop length for the onset envelope. Default 512. */\n hopLength?: number;\n /** Number of tempo candidates to return. Default 5. */\n maxCandidates?: number;\n}\n\n/** Options for `analyzeRhythm`. All fields are optional. */\nexport interface AnalyzeRhythmOptions extends ValidateOptions {\n /** Lowest BPM to consider. Default 60. */\n bpmMin?: number;\n /** Highest BPM to consider. Default 200. */\n bpmMax?: number;\n /** Tempo prior the tracker is biased toward. Default 120. */\n startBpm?: number;\n /** FFT size for the onset envelope. Default 2048. */\n nFft?: number;\n /** Hop length for the onset envelope. Default 512. */\n hopLength?: number;\n}\n\n/** Options for `analyzeDynamics`. All fields are optional. */\nexport interface AnalyzeDynamicsOptions extends ValidateOptions {\n /** Loudness-curve window length in seconds. Default 0.4. */\n windowSec?: number;\n /** Hop length for the loudness curve. Default 512. */\n hopLength?: number;\n /** Crest-factor (dB) below which the signal is flagged as compressed. Default 6. */\n compressionThreshold?: number;\n}\n\n/** Options for `analyzeTimbre`. All fields are optional. */\nexport interface AnalyzeTimbreOptions extends ValidateOptions {\n /** FFT size. Default 2048. */\n nFft?: number;\n /** Hop length. Default 512. */\n hopLength?: number;\n /** Number of Mel bands. Default 128. */\n nMels?: number;\n /** Number of MFCCs. Default 13. */\n nMfcc?: number;\n /** Per-window analysis length in seconds. Default 0.5. */\n windowSec?: number;\n}\n\n/** Options for `analyzeSections`. All fields are optional. */\nexport interface AnalyzeSectionsOptions {\n /** FFT size. Default 2048. */\n nFft?: number;\n /** Hop length. Default 512. */\n hopLength?: number;\n /** Minimum section duration in seconds. Default 4. */\n minSectionSec?: number;\n}\n\n/**\n * Detected beat\n */\nexport interface Beat {\n /** Beat position in seconds. */\n time: number;\n /**\n * Onset-envelope value sampled at the beat's frame.\n *\n * @remarks\n * A single raw frame of the onset envelope, not a normalized or relative\n * salience: it is unbounded, its scale depends on the material, and it moves\n * with any jitter in the beat position. For accent scoring use\n * {@link BeatObservations.onsetStrength}, which is the windowed aggregate the\n * library's own downbeat pass scores.\n */\n strength: number;\n}\n\n/**\n * Beat-level evidence behind the downbeat and meter decisions.\n *\n * @remarks\n * These are inputs to the library's decision, not outputs of it, exposed so a\n * caller running its own meter work scores the same evidence instead of\n * reconstructing a weaker approximation from the frame-level onset envelope.\n * Each non-empty stream holds one value per entry of\n * {@link AnalysisResult.beats} and indexes in parallel with it. An empty stream\n * means the analysis could not produce it, which is not the same as every beat\n * having scored zero.\n */\nexport interface BeatObservations {\n /**\n * Beat-local onset-strength window.\n *\n * @remarks\n * Unlike {@link Beat.strength} this is aggregated over a window around the\n * beat rather than sampled at a single frame, so it is the stream to score\n * accents with.\n */\n onsetStrength: number[];\n /**\n * Beat-local low-frequency energy — the accent evidence a log-spectral\n * difference discards. Empty when the analysis ran without audio.\n */\n lowFrequencyEnergy: number[];\n /** Per-beat chord-change evidence. Empty until chords are analyzed. */\n chordChange: number[];\n}\n\n/**\n * Detected chord\n */\nexport interface Chord {\n root: PitchClass;\n bass: PitchClass;\n /** Canonical core spelling; stable across all language bindings. */\n rootName: string;\n /** Canonical core spelling; stable across all language bindings. */\n bassName: string;\n quality: ChordQuality;\n start: number;\n end: number;\n /** Derived from `end - start`; the core carries only the two endpoints. */\n duration: number;\n confidence: number;\n name: string;\n}\n\n/** A chord in {@link AnalysisResult.chords}, which carries its function in the key. */\nexport interface AnalysisChord extends Chord {\n /**\n * Roman numeral of the chord relative to {@link AnalysisResult.key}, e.g.\n * `'V7'`, `'vi'`, `'bVII'`. The same spelling `chordFunctionalAnalysis`\n * returns for that chord and key. Empty for a chord that is N.C.\n */\n romanNumeral: string;\n}\n\nexport interface ChordAnalysisResult {\n chords: Chord[];\n}\n\n/**\n * Detected section\n */\nexport interface Section {\n type: SectionType;\n start: number;\n end: number;\n energyLevel: number;\n confidence: number;\n name: string;\n}\n\n/** Options for `detectBoundaries`. All fields are optional. */\nexport interface BoundaryOptions {\n /** FFT size used for the structural features. Default 2048. */\n nFft?: number;\n /** Hop length in samples. Default 512. */\n hopLength?: number;\n /** Checkerboard kernel size in frames. Default 64. */\n kernelSize?: number;\n /**\n * Relative novelty threshold, applied to the curve after it has been scaled by\n * its own maximum. Selects how prominent a peak must be *within this track*; it\n * says nothing about how much the features actually changed. Default 0.3.\n */\n threshold?: number;\n /**\n * Novelty floor applied to the raw response before that scaling, asking whether\n * anything changed at all. Default 0.005. Set to 0 to gate on {@link threshold}\n * alone -- but self-scaling turns residual fluctuation into peaks of 1.0, so a\n * stationary input then segments anyway. Lowering the floor does not recover\n * level-only structure: a level change turns the feature vector about five times\n * less than a comparable pitch change, landing below what steady noise produces,\n * so the noise is admitted first.\n */\n absoluteThreshold?: number;\n /** Number of MFCC coefficients. Default 13. */\n nMfcc?: number;\n /** Number of chroma bins. Default 12. */\n nChroma?: number;\n /** Minimum spacing between peaks, in seconds. Default 2. */\n peakDistance?: number;\n /** Use MFCC features. Default `true`. */\n useMfcc?: boolean;\n /** Use chroma features. Default `true`. */\n useChroma?: boolean;\n}\n\n/**\n * A single detected structural boundary (mirrors the C `SonareBoundary`).\n */\nexport interface Boundary {\n /** Boundary time in seconds (the authoritative output). */\n time: number;\n /**\n * Index into the analysis grid, on {@link BoundaryResult.sampleRate}'s time\n * base rather than the source's. For a long-form input the feature grid is\n * additionally mean-pooled, so this indexes the pooled grid; use `time` for\n * sample/second mapping either way.\n */\n frame: number;\n /** Boundary strength (novelty score). */\n strength: number;\n}\n\n/**\n * Result of `detectBoundaries` (mirrors the C `SonareBoundaryResult`).\n */\nexport interface BoundaryResult {\n /** Detected transitions, in time order. */\n boundaries: Boundary[];\n /**\n * Novelty curve scaled by its own maximum, one value per analysis frame. A\n * peak of 1 means \"the most novel frame here\", not \"a large change\"; multiply\n * by {@link noveltyPeak} to recover the raw response\n * {@link BoundaryOptions.absoluteThreshold} is compared against.\n */\n noveltyCurve: Float32Array;\n /**\n * The largest raw checkerboard response, before normalization. Zero when the\n * curve was left unnormalized because nothing rose above the numerical floor.\n */\n noveltyPeak: number;\n /**\n * The rate the analysis ran at, not the input's: a source above 22050 Hz is\n * resampled to 22050 Hz before any feature is computed, which is what makes\n * {@link Boundary.frame} interpretable.\n */\n sampleRate: number;\n /** Hop length the analysis grid was built on. */\n hopLength: number;\n /** Analysis frame count, pooled for a long-form input. */\n nFrames: number;\n /**\n * Feature pooling stride: 1 for every realistic input length, otherwise the\n * number of raw STFT frames averaged into each analysis frame.\n */\n frameStride: number;\n}\n\n/**\n * A single melody contour point (mirrors the C `SonareMelodyPoint`).\n */\nexport interface MelodyPoint {\n /** Frame time in seconds. */\n time: number;\n /** Estimated fundamental frequency in Hz (0 when unvoiced). */\n frequency: number;\n /** Voicing confidence in `[0, 1]`. */\n confidence: number;\n}\n\n/**\n * Melody analysis result (mirrors the C `SonareMelodyResult`).\n */\nexport interface MelodyResult {\n points: MelodyPoint[];\n pitchRangeOctaves: number;\n pitchStability: number;\n meanFrequency: number;\n vibratoRate: number;\n}\n\n/**\n * Timbre characteristics\n */\nexport interface Timbre {\n brightness: number;\n warmth: number;\n density: number;\n roughness: number;\n complexity: number;\n}\n\n/**\n * Dynamics characteristics\n */\nexport interface Dynamics {\n dynamicRangeDb: number;\n peakDb: number;\n rmsDb: number;\n loudnessRangeDb: number;\n crestFactor: number;\n isCompressed: boolean;\n}\n\n/**\n * Time signature\n */\nexport interface TimeSignature {\n numerator: number;\n denominator: number;\n /**\n * Support for this signature in `[0, 1]`.\n *\n * @remarks\n * What it measures depends on which field the signature arrived in. On\n * {@link MeterEstimate.timeSignature} it is derived from the margin over the\n * runner-up; on a {@link MeterEstimate.candidates} entry it is that\n * candidate's share of the summed support. The two are not comparable, so\n * read the value from the field you meant rather than from whichever one is\n * to hand.\n */\n confidence: number;\n}\n\n/**\n * Meter estimated over a caller-supplied beat series.\n */\nexport interface MeterEstimate {\n /**\n * Selected time signature.\n *\n * @remarks\n * Its `confidence` is the margin over the runner-up — how separated the\n * winner is — not the share-of-support a {@link candidates} entry carries\n * under the same field name.\n */\n timeSignature: TimeSignature;\n /** Beat index the first measure starts on, in `[0, timeSignature.numerator)`. */\n downbeatPhase: number;\n /**\n * Whether a search ran, as opposed to the fixed fallback being reported.\n *\n * @remarks\n * `false` means the beat series was too short to score any candidate, and\n * every other field then carries that fallback rather than a measurement —\n * `timeSignature.confidence` included, which is 0, so an unchecked read\n * degrades toward \"no idea\" rather than toward a middling detection. Read\n * this before treating a short span's answer as a detection.\n */\n searched: boolean;\n /**\n * How the bar divides, in beats per accent group.\n *\n * @remarks\n * `[3, 2, 2]` is the 7/8 an aksak meter notates as 3+2+2, and `[2, 2]` an\n * ordinary four. Always sums to `timeSignature.numerator`.\n *\n * A single entry means no internal division was resolved — the numerator has\n * none to find, it was too wide to search, or the span was too short to\n * search at all.\n *\n * This is also what tells a compound bar from a simple one: per-beat accents\n * cannot say how a beat subdivides, so a six accented 3+3 keeps the requested\n * denominator and reports `[3, 3]` rather than being promoted to 6/8.\n */\n grouping: number[];\n /**\n * Multi-comb score per requested candidate numerator.\n *\n * @remarks\n * Parallel to the `candidateNumerators` that were requested, in the order\n * they were given. This does NOT index alike with {@link candidates}, which\n * is ordered by descending support.\n *\n * Standardized and signed: zero is the level a numerator reaches on beats\n * carrying no meter, so a negative entry means less support than noise would\n * produce. Only the ordering and the gaps between entries carry meaning.\n *\n * Comparable only within one result. A score grows with the square root of\n * how many beats were scored, so the same meter over twice the beats scores\n * about 1.41 times as high; a segmentation search comparing spans of\n * different lengths has to normalize for length first.\n */\n candidateScores: number[];\n /**\n * Candidate signatures ordered by descending support.\n *\n * @remarks\n * A ranking, so entry `k` is the k-th best hypothesis — not the k-th\n * requested numerator. Use {@link candidateScores} to read the score of a\n * specific requested numerator.\n *\n * Each entry's `confidence` is that candidate's share of the summed support,\n * so the entries sum to one. It is a different quantity from\n * {@link timeSignature}'s margin-derived confidence, which shares the field\n * name and nothing else.\n */\n candidates: TimeSignature[];\n}\n\n/** Existing tempo-estimator hypothesis retained by unified analysis. */\nexport interface BpmHypothesis {\n value: number;\n confidence: number;\n relation: 'primary' | 'half' | 'double' | 'other';\n}\n\n/**\n * Rhythm features\n */\nexport interface RhythmFeatures {\n syncopation: number;\n grooveType: string;\n patternRegularity: number;\n tempoStability: number;\n timeSignature: TimeSignature;\n}\n\n/**\n * Melody contour from the unified analysis (pitch trajectory + summary stats).\n */\nexport interface MelodyContour {\n pitchRangeOctaves: number;\n pitchStability: number;\n meanFrequency: number;\n vibratoRate: number;\n pitches: MelodyPoint[];\n}\n\n/**\n * Complete analysis result\n */\nexport interface AnalysisResult {\n bpm: number;\n bpmConfidence: number;\n bpmCandidates: BpmHypothesis[];\n key: Key;\n timeSignature: TimeSignature;\n timeSignatureCandidates: TimeSignature[];\n beatTimes: Float32Array;\n beats: Beat[];\n /**\n * Indices into {@link AnalysisResult.beats} that fall on a measure start.\n *\n * @remarks\n * Not the same length as `beats` — it holds one entry per detected downbeat,\n * and each entry indexes `beats`, so `beats[downbeatIndices[k]]` is the k-th\n * downbeat. Testing a beat for downbeat status is a membership check on this\n * list rather than a time comparison against a separate downbeat series.\n */\n downbeatIndices: number[];\n /**\n * Beat index the first measure starts on, in `[0, timeSignature.numerator)`.\n *\n * @remarks\n * The meter estimator's phase, so `downbeatIndices` normally begins at this\n * value. It is not re-derived when downbeats are refined from chord and\n * low-frequency-energy evidence, so the two can disagree when the refinement\n * moves the first measure start.\n */\n downbeatPhase: number;\n /**\n * Beat-level evidence behind the downbeat and meter decisions, parallel to\n * {@link AnalysisResult.beats}.\n */\n beatObservations: BeatObservations;\n /**\n * Smoothed local tempo at each beat, in BPM, parallel to\n * {@link AnalysisResult.beats}.\n *\n * @remarks\n * Empty unless `computeTempoCurve` was set, and empty regardless when fewer\n * than two beats were detected, since a tempo is a property of the interval\n * between two beats. The last entry repeats the tempo of the interval leading\n * into the final beat, which opens no interval of its own.\n *\n * Values are continuous, not points on a tempo grid: each is a weighted\n * average, in log tempo, of the beat intervals around it. A steady tempo\n * reads within about 1% at every beat, and a tempo that moves is followed a\n * few beats late.\n *\n * This is the local tempo rather than {@link AnalysisResult.bpm} resampled:\n * on material whose tempo moves it departs from `bpm`, and reading a single\n * number out of it is not how to get the global tempo.\n */\n beatLocalBpm: number[];\n chords: AnalysisChord[];\n sections: Section[];\n timbre: Timbre;\n dynamics: Dynamics;\n rhythm: RhythmFeatures;\n melody: MelodyContour;\n form: string;\n}\n","import { resolveEnumOrdinal } from './codes';\nimport type {\n AnalysisResult,\n ChordAnalysisResult,\n ChordDetectionOptions,\n ChordQuality,\n KeyCandidate,\n KeyDetectionOptions,\n KeyProfileName,\n PitchClass,\n SectionType,\n} from './public_types';\nimport { KeyProfile as KeyProfileValues, Mode } from './public_types';\nimport type {\n WasmAnalysisResult,\n WasmChordAnalysisResult,\n WasmKeyCandidateResult,\n} from './sonare.js';\n\nconst PITCH_CLASS_NAMES = [\n 'C',\n 'C#',\n 'D',\n 'D#',\n 'E',\n 'F',\n 'F#',\n 'G',\n 'G#',\n 'A',\n 'A#',\n 'B',\n] as const;\n\nfunction pitchClassName(value: number): string {\n return PITCH_CLASS_NAMES[value] ?? 'C';\n}\n\nexport function convertKeyCandidate(wasm: WasmKeyCandidateResult): KeyCandidate {\n return {\n key: {\n root: wasm.key.root as PitchClass,\n mode: wasm.key.mode as Mode,\n confidence: wasm.key.confidence,\n name: wasm.key.name,\n shortName: wasm.key.shortName,\n },\n correlation: wasm.correlation,\n };\n}\n\n// Consolidated spelling -> ordinal tables, resolved through the same\n// resolveEnumOrdinal() primitive as panModeCode/panLawCode/etc. in ./codes.\n// An unmapped string or an out-of-range numeric ordinal throws RangeError\n// instead of silently resolving to `undefined` (which used to reach the WASM\n// layer as a mistyped argument) or passing an unvalidated raw number through.\nconst KEY_MODE_VALUES: Readonly<Record<string, number>> = {\n major: Mode.Major,\n minor: Mode.Minor,\n dorian: Mode.Dorian,\n phrygian: Mode.Phrygian,\n lydian: Mode.Lydian,\n mixolydian: Mode.Mixolydian,\n locrian: Mode.Locrian,\n};\n\nconst KEY_PROFILE_VALUES: Readonly<Record<KeyProfileName, number>> = {\n ks: KeyProfileValues.KrumhanslSchmuckler,\n krumhansl: KeyProfileValues.KrumhanslSchmuckler,\n temperley: KeyProfileValues.Temperley,\n shaath: KeyProfileValues.Shaath,\n keyfinder: KeyProfileValues.Shaath,\n 'faraldo-edmt': KeyProfileValues.FaraldoEDMT,\n edmt: KeyProfileValues.FaraldoEDMT,\n 'faraldo-edma': KeyProfileValues.FaraldoEDMA,\n edma: KeyProfileValues.FaraldoEDMA,\n 'faraldo-edmm': KeyProfileValues.FaraldoEDMM,\n edmm: KeyProfileValues.FaraldoEDMM,\n 'bellman-budge': KeyProfileValues.BellmanBudge,\n bellman: KeyProfileValues.BellmanBudge,\n};\n\nexport function keyModeValues(modes: KeyDetectionOptions['modes'] | undefined): number[] {\n if (!modes) {\n return [];\n }\n if (modes === 'major-minor') {\n return [Mode.Major, Mode.Minor];\n }\n if (modes === 'all' || modes === 'modal') {\n return [\n Mode.Major,\n Mode.Minor,\n Mode.Dorian,\n Mode.Phrygian,\n Mode.Lydian,\n Mode.Mixolydian,\n Mode.Locrian,\n ];\n }\n return modes.map((mode) => resolveEnumOrdinal(mode, KEY_MODE_VALUES, 'key mode'));\n}\n\nexport function keyProfileValue(profile: KeyDetectionOptions['profile'] | undefined): number {\n if (profile === undefined) {\n return -1;\n }\n return resolveEnumOrdinal(profile, KEY_PROFILE_VALUES, 'key profile');\n}\n\nexport function convertChordAnalysisResult(wasm: WasmChordAnalysisResult): ChordAnalysisResult {\n return {\n chords: wasm.chords.map((c) => ({\n root: c.root as PitchClass,\n bass: c.bass as PitchClass,\n rootName: pitchClassName(c.root),\n bassName: pitchClassName(c.bass),\n quality: c.quality as ChordQuality,\n start: c.start,\n end: c.end,\n duration: c.end - c.start,\n confidence: c.confidence,\n name: c.name,\n })),\n };\n}\n\nexport function chordChromaMethodValue(method: ChordDetectionOptions['chromaMethod']): number {\n if (method === 'stft') {\n return 0;\n }\n if (method === 'nnls') {\n return 1;\n }\n throw new Error(`Invalid chord chroma method: ${method}`);\n}\n\nexport function convertAnalysisResult(wasm: WasmAnalysisResult): AnalysisResult {\n const beatTimes = new Float32Array(wasm.beats.length);\n for (let i = 0; i < wasm.beats.length; i++) {\n beatTimes[i] = wasm.beats[i].time;\n }\n return {\n bpm: wasm.bpm,\n bpmConfidence: wasm.bpmConfidence,\n bpmCandidates: wasm.bpmCandidates.map((candidate) => ({\n value: candidate.value,\n confidence: candidate.confidence,\n relation: candidate.relation,\n })),\n key: {\n root: wasm.key.root as PitchClass,\n mode: wasm.key.mode as Mode,\n confidence: wasm.key.confidence,\n name: wasm.key.name,\n shortName: wasm.key.shortName,\n },\n timeSignature: wasm.timeSignature,\n timeSignatureCandidates: wasm.timeSignatureCandidates,\n beatTimes,\n beats: wasm.beats,\n downbeatIndices: wasm.downbeatIndices,\n downbeatPhase: wasm.downbeatPhase,\n beatObservations: wasm.beatObservations,\n beatLocalBpm: wasm.beatLocalBpm,\n chords: wasm.chords.map((c) => ({\n root: c.root as PitchClass,\n bass: c.bass as PitchClass,\n rootName: pitchClassName(c.root),\n bassName: pitchClassName(c.bass),\n quality: c.quality as ChordQuality,\n start: c.start,\n end: c.end,\n duration: c.end - c.start,\n confidence: c.confidence,\n name: c.name,\n romanNumeral: c.romanNumeral,\n })),\n sections: wasm.sections.map((s) => ({\n type: s.type as SectionType,\n start: s.start,\n end: s.end,\n energyLevel: s.energyLevel,\n confidence: s.confidence,\n name: s.name,\n })),\n timbre: wasm.timbre,\n dynamics: wasm.dynamics,\n rhythm: wasm.rhythm,\n melody: wasm.melody,\n form: wasm.form,\n };\n}\n","import {\n chordChromaMethodValue,\n convertAnalysisResult,\n convertChordAnalysisResult,\n convertKeyCandidate,\n keyModeValues,\n keyProfileValue,\n} from './analysis_helpers';\nimport { getSonareModule } from './module_state';\nimport type {\n AcousticOptions,\n AcousticResult,\n AnalysisResult,\n AnalyzeBpmOptions,\n AnalyzeDynamicsOptions,\n AnalyzeRhythmOptions,\n AnalyzeTimbreOptions,\n ChordAnalysisResult,\n ChordDetectionOptions,\n Key,\n KeyCandidate,\n KeyDetectionOptions,\n MeterEstimate,\n RirResult,\n RirSynthOptions,\n RoomEstimateOptions,\n RoomEstimateResult,\n RoomMorphOptions,\n RoomMorphResult,\n} from './public_types';\nimport { Mode, PitchClass } from './public_types';\nimport type { ProgressCallback, WasmAcousticResult } from './sonare.js';\nimport type { ValidateOptions } from './validation';\nimport {\n assertFiniteScalar,\n assertNonNegativeInteger,\n assertSampleRate,\n assertSamples,\n} from './validation';\n\nfunction requireModule() {\n return getSonareModule();\n}\n\ntype GuardedOptions = ValidateOptions;\n\n/** Canonical request form for one-shot analysis functions. */\nexport interface SamplesRequest extends GuardedOptions {\n samples: Float32Array;\n sampleRate?: number;\n}\n\n/** Peak-picking configuration for {@link detectOnsets}. */\nexport interface OnsetDetectOptions {\n nFft?: number;\n hopLength?: number;\n threshold?: number;\n preMax?: number;\n postMax?: number;\n preAvg?: number;\n postAvg?: number;\n delta?: number;\n wait?: number;\n backtrack?: boolean;\n backtrackRange?: number;\n}\nexport interface DetectOnsetsRequest extends SamplesRequest, OnsetDetectOptions {}\n\n/** Canonical request form for key detection functions. */\nexport interface DetectKeyRequest extends KeyDetectionOptions, SamplesRequest {}\n\n/** Canonical request form for analysis with synchronous progress reporting. */\nexport interface AnalyzeWithProgressRequest extends SamplesRequest {\n onProgress?: ProgressCallback;\n cancel?: () => boolean;\n /** Analysis options, with the same fields and defaults {@link analyze} takes. */\n options?: MusicAnalyzeOptions;\n}\n\n/** Canonical request form for chord detection. */\nexport interface DetectChordsRequest extends ChordDetectionOptions, SamplesRequest {}\n\n/** Canonical request form for functional chord analysis. */\nexport interface ChordFunctionalAnalysisRequest extends DetectChordsRequest {\n keyRoot: PitchClass;\n /** Musical mode; defaults to {@link Mode.Major}. */\n keyMode?: Mode;\n}\n\n/** Canonical request form for impulse-response analysis. */\nexport interface AnalyzeImpulseResponseRequest extends SamplesRequest {\n nOctaveBands?: number;\n minDecayDb?: number;\n}\n\n/** Canonical request form for acoustic analysis. */\nexport interface DetectAcousticRequest extends AcousticOptions, SamplesRequest {}\n\n/** Canonical request form for equivalent-room estimation. */\nexport interface EstimateRoomRequest extends RoomEstimateOptions, SamplesRequest {}\n\n/** Canonical request form for room-reverb morphing. */\nexport interface RoomMorphRequest extends RoomMorphOptions, GuardedOptions {\n samples: Float32Array;\n sampleRate: number;\n}\n\n/** Canonical request forms for detailed music-analysis APIs. */\nexport interface AnalyzeBpmRequest extends AnalyzeBpmOptions, SamplesRequest {}\nexport interface AnalyzeRhythmRequest extends AnalyzeRhythmOptions, SamplesRequest {}\nexport interface AnalyzeDynamicsRequest extends AnalyzeDynamicsOptions, SamplesRequest {}\nexport interface AnalyzeTimbreRequest extends AnalyzeTimbreOptions, SamplesRequest {}\n\nfunction validateAnalysisInput(\n fnName: string,\n samples: Float32Array,\n sampleRate: number,\n options: GuardedOptions = {},\n): void {\n assertSampleRate(fnName, sampleRate);\n assertSamples(fnName, samples, options.validate !== false);\n}\n\n// ============================================================================\n// Quick API (High-level Analysis)\n// ============================================================================\n\n/**\n * Detect BPM from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Detected BPM\n */\nexport function detectBpm(request: SamplesRequest): number;\nexport function detectBpm(\n samples: Float32Array,\n sampleRate?: number,\n options?: GuardedOptions,\n): number;\nexport function detectBpm(\n samples: Float32Array | SamplesRequest,\n sampleRate = 22050,\n options: GuardedOptions = {},\n): number {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectBpm', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().detectBpm(request.samples, request.sampleRate ?? 22050);\n}\n\n/**\n * Detect musical key from audio samples.\n *\n * The chroma is read at concert A440; a tuning offset is applied through\n * {@link analyze}'s `tuning` option (and to chords through {@link detectChords}).\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Detected key\n */\nexport function detectKey(request: DetectKeyRequest): Key;\nexport function detectKey(\n samples: Float32Array,\n sampleRate?: number,\n options?: KeyDetectionOptions,\n): Key;\nexport function detectKey(\n samples: Float32Array | DetectKeyRequest,\n sampleRate = 22050,\n options: KeyDetectionOptions = {},\n): Key {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectKey', request.samples, request.sampleRate ?? 22050, request);\n const result = requireModule()._detectKeyWithOptions(\n request.samples,\n request.sampleRate ?? 22050,\n request.nFft ?? 4096,\n request.hopLength ?? 512,\n request.useHpss ?? false,\n request.loudnessWeighted ?? false,\n request.highPassHz ?? 0,\n keyModeValues(request.modes),\n keyProfileValue(request.profile),\n request.genreHint ?? '',\n );\n return {\n root: result.root as PitchClass,\n mode: result.mode as Mode,\n confidence: result.confidence,\n name: result.name,\n shortName: result.shortName,\n };\n}\n\nexport function detectKeyCandidates(request: DetectKeyRequest): KeyCandidate[];\nexport function detectKeyCandidates(\n samples: Float32Array,\n sampleRate?: number,\n options?: KeyDetectionOptions,\n): KeyCandidate[];\nexport function detectKeyCandidates(\n samples: Float32Array | DetectKeyRequest,\n sampleRate = 22050,\n options: KeyDetectionOptions = {},\n): KeyCandidate[] {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput(\n 'detectKeyCandidates',\n request.samples,\n request.sampleRate ?? 22050,\n request,\n );\n // The embind value marshalling returns an array whose constructor is not this\n // realm's Array; chaining .map() onto it propagates that constructor via\n // Symbol.species, leaving a result that structuredClone (and so postMessage to\n // a Worker) rejects with \"could not be cloned\". Array.from() re-roots it as a\n // plain Array before mapping.\n const candidates = requireModule()._detectKeyCandidates(\n request.samples,\n request.sampleRate ?? 22050,\n request.nFft ?? 4096,\n request.hopLength ?? 512,\n request.useHpss ?? false,\n request.loudnessWeighted ?? false,\n request.highPassHz ?? 0,\n keyModeValues(request.modes),\n keyProfileValue(request.profile),\n request.genreHint ?? '',\n );\n return Array.from(candidates, convertKeyCandidate);\n}\n\n/**\n * Detect onset times from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Array of onset times in seconds\n */\nexport function detectOnsets(request: DetectOnsetsRequest): Float32Array;\nexport function detectOnsets(\n samples: Float32Array,\n sampleRate?: number,\n options?: OnsetDetectOptions & GuardedOptions,\n): Float32Array;\nexport function detectOnsets(\n samples: Float32Array | DetectOnsetsRequest,\n sampleRate = 22050,\n options: OnsetDetectOptions & GuardedOptions = {},\n): Float32Array {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectOnsets', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().detectOnsets(request.samples, request.sampleRate ?? 22050, request);\n}\n\n/**\n * Detect beat times from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Array of beat times in seconds\n */\nexport function detectBeats(request: SamplesRequest): Float32Array;\nexport function detectBeats(\n samples: Float32Array,\n sampleRate?: number,\n options?: GuardedOptions,\n): Float32Array;\nexport function detectBeats(\n samples: Float32Array | SamplesRequest,\n sampleRate = 22050,\n options: GuardedOptions = {},\n): Float32Array {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectBeats', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().detectBeats(request.samples, request.sampleRate ?? 22050);\n}\n\n/**\n * Detect downbeat times from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Array of downbeat times in seconds\n */\nexport function detectDownbeats(request: SamplesRequest): Float32Array;\nexport function detectDownbeats(\n samples: Float32Array,\n sampleRate?: number,\n options?: GuardedOptions,\n): Float32Array;\nexport function detectDownbeats(\n samples: Float32Array | SamplesRequest,\n sampleRate = 22050,\n options: GuardedOptions = {},\n): Float32Array {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectDownbeats', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().detectDownbeats(request.samples, request.sampleRate ?? 22050);\n}\n\n/**\n * Detect chords from audio samples.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param options - Optional chord detection settings\n * @returns Detected chord segments\n */\nexport function detectChords(request: DetectChordsRequest): ChordAnalysisResult;\nexport function detectChords(\n samples: Float32Array,\n sampleRate?: number,\n options?: ChordDetectionOptions,\n): ChordAnalysisResult;\nexport function detectChords(\n samples: Float32Array | DetectChordsRequest,\n sampleRate = 22050,\n options: ChordDetectionOptions = {},\n): ChordAnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectChords', request.samples, request.sampleRate ?? 22050, request);\n const result = requireModule().detectChords(\n request.samples,\n request.sampleRate ?? 22050,\n request.minDuration ?? 0.3,\n request.smoothingWindow ?? 2.0,\n request.threshold ?? 0.5,\n request.useTriadsOnly ?? false,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n request.useBeatSync ?? true,\n request.useHmm ?? false,\n request.hmmBeamWidth ?? 24,\n request.useKeyContext ?? false,\n request.keyRoot ?? PitchClass.C,\n request.keyMode ?? Mode.Major,\n request.detectInversions ?? false,\n chordChromaMethodValue(request.chromaMethod ?? 'stft'),\n request.tuning ?? 0,\n );\n return convertChordAnalysisResult(result);\n}\n\n/**\n * Functional (Roman-numeral) harmonic analysis of the detected chord\n * progression, relative to the given key. Mirrors the C-ABI\n * `sonare_chord_functional_analysis` and the Node/Python `chordFunctionalAnalysis`.\n *\n * @returns One Roman-numeral label (e.g. \"I\", \"IV\", \"V\", \"vi\") per detected chord\n */\nexport function chordFunctionalAnalysis(request: ChordFunctionalAnalysisRequest): string[];\nexport function chordFunctionalAnalysis(\n samples: Float32Array,\n keyRoot: PitchClass,\n keyMode?: Mode,\n sampleRate?: number,\n options?: ChordDetectionOptions,\n): string[];\nexport function chordFunctionalAnalysis(\n samples: Float32Array | ChordFunctionalAnalysisRequest,\n keyRoot?: PitchClass,\n keyMode?: Mode,\n sampleRate = 22050,\n options: ChordDetectionOptions = {},\n): string[] {\n const request =\n samples instanceof Float32Array\n ? { samples, keyRoot, keyMode, sampleRate, ...options }\n : samples;\n validateAnalysisInput(\n 'chordFunctionalAnalysis',\n request.samples,\n request.sampleRate ?? 22050,\n request,\n );\n return requireModule().chordFunctionalAnalysis(\n request.samples,\n request.keyRoot as PitchClass,\n request.keyMode ?? Mode.Major,\n request.sampleRate ?? 22050,\n request.minDuration ?? 0.3,\n request.smoothingWindow ?? 2.0,\n request.threshold ?? 0.5,\n request.useTriadsOnly ?? false,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n request.useBeatSync ?? true,\n request.useHmm ?? false,\n request.hmmBeamWidth ?? 24,\n request.useKeyContext ?? false,\n request.detectInversions ?? false,\n chordChromaMethodValue(request.chromaMethod ?? 'stft'),\n request.tuning ?? 0,\n );\n}\n\n/**\n * Options for {@link analyze}. Every field is optional and falls back to the\n * core default when omitted.\n */\nexport interface MusicAnalyzeOptions {\n nFft?: number;\n hopLength?: number;\n bpmMin?: number;\n bpmMax?: number;\n startBpm?: number;\n useTriadsOnly?: boolean;\n useHpss?: boolean;\n chromaHighpassHz?: number;\n useBassWeighted?: boolean;\n chromaHopMultiplier?: number;\n useChordHmm?: boolean;\n useChordKeyContext?: boolean;\n chordHmmBeamWidth?: number;\n detectChordInversions?: boolean;\n /**\n * Track a locally updated tempo prior during beat tracking (default: false).\n */\n adaptiveTempo?: boolean;\n /**\n * Length of the local tempo context in beats (default: 8). Must be positive.\n */\n tempoUpdateIntervalBeats?: number;\n /**\n * Decode a per-beat local tempo curve into\n * {@link AnalysisResult.beatLocalBpm} (default: false).\n *\n * @remarks\n * Off by default because it is an extra output rather than a better analysis:\n * nothing else in the result changes, and a caller that does not read the\n * curve would pay a decode over the beat grid for nothing.\n *\n * The curve describes the beat grid it was decoded from, and beat tracking\n * holds a fixed tempo prior unless {@link MusicAnalyzeOptions.adaptiveTempo}\n * is also set, so measuring a tempo that moves needs both.\n */\n computeTempoCurve?: boolean;\n /**\n * Meter numerators the estimator scores (default: `[3, 4, 6]`).\n *\n * @remarks\n * Adding a numerator widens the search; it does not force the result. The\n * list must hold between 1 and 16 entries, each in `[2, 32]`.\n */\n meterCandidateNumerators?: number[];\n /**\n * Beat unit reported for the detected meter (default: 4). Must be a power of\n * two in `[1, 32]`. The estimator still reports 8 on its own when it resolves\n * a compound meter, so this is the unit for everything else.\n */\n meterDenominator?: number;\n /**\n * Tuning offset of the recording in fractions of a semitone, the unit\n * `estimateTuning` returns; must be in `[-0.5, 0.5)`. Every chroma the\n * analysis builds (key, chords, sections) is shifted by it, so a recording\n * that is not at A440 reads its key and chords on its own pitch grid.\n * Default 0 (concert A440).\n */\n tuning?: number;\n}\nexport interface MusicAnalyzeRequest extends SamplesRequest, MusicAnalyzeOptions {}\n\n/**\n * Perform complete music analysis.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @returns Complete analysis result\n *\n * @remarks\n * This call is synchronous and blocks until analysis completes. Unlike the\n * Node binding (which offers `analyzeAsync` on a libuv worker thread), the\n * WASM build runs on a single thread, so there is no non-blocking variant —\n * the DSP pipeline always runs to completion on the calling thread. To keep\n * the UI responsive for long inputs, drive this from a Web Worker and use\n * {@link analyzeWithProgress} to report progress.\n */\nexport function analyze(request: MusicAnalyzeRequest): AnalysisResult;\nexport function analyze(\n samples: Float32Array,\n sampleRate?: number,\n options?: GuardedOptions & MusicAnalyzeOptions,\n): AnalysisResult;\nexport function analyze(\n samples: Float32Array | MusicAnalyzeRequest,\n sampleRate = 22050,\n options: GuardedOptions & MusicAnalyzeOptions = {},\n): AnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyze', request.samples, request.sampleRate ?? 22050, request);\n const result = requireModule().analyze(request.samples, request.sampleRate ?? 22050, request);\n return convertAnalysisResult(result);\n}\n\n/**\n * Canonical request form for {@link estimateMeter}.\n *\n * @remarks\n * Every scoring field is optional and falls back to the core default when\n * omitted; the core validates them and rejects a value it cannot answer rather\n * than substituting one.\n */\nexport interface EstimateMeterRequest {\n /** Beat positions in seconds, non-decreasing. */\n beatTimes: ArrayLike<number>;\n /**\n * Per-beat accent value, the same length as {@link beatTimes}.\n *\n * @remarks\n * `AnalysisResult.beatObservations.onsetStrength` is the intended source —\n * it is the windowed value the library's own downbeat pass scores.\n * `beats[].strength` also works but is a single unwindowed envelope frame.\n * Neither needs pre-scaling: the series is divided by its own maximum before\n * scoring, so only the accent contrast within it is read.\n *\n * A series assembled by hand from {@link onsetEnvelope} — one frame read at\n * each beat time — is neither of those, and it carries a sample-rate\n * dependence neither of them has: a hop counted in samples frames a different\n * amount of time at each rate, so one waveform sampled at 32000, 44100 and\n * 48000 Hz has produced three different winning numerators off beat times\n * identical to the sample. Widening the read to a window around the beat does\n * not remove it. A browser decodes at the output device's rate, so that is a\n * different answer per visitor for the same clip.\n */\n beatStrengths: ArrayLike<number>;\n /**\n * Meter numerators to score (default: `[3, 4, 6]`).\n *\n * @remarks\n * Adding a numerator widens the search; it does not force the result. The\n * list must hold between 1 and 16 entries, each in `[2, 32]`.\n */\n candidateNumerators?: number[];\n /**\n * Beat unit reported for the detected meter (default: 4). Must be a power of\n * two in `[1, 32]`.\n *\n * @remarks\n * Reported as requested: whether a beat divides into three is measured from\n * energy *between* the beats, which per-beat accents do not carry, so a\n * compound meter is not resolvable here. A six accented 3+3 comes back with\n * this denominator and `grouping === [3, 3]`.\n */\n denominator?: number;\n /** Weight of the downbeat accent term (default: 1). */\n downbeatWeight?: number;\n /** Weight of the measure-periodicity term (default: 0.5). */\n measureWeight?: number;\n /** Weight of the subdivision term (default: 0.15). */\n subdivisionWeight?: number;\n /**\n * Score ratio above which a compound meter is preferred (default: 0.85).\n *\n * @remarks\n * Only consulted when there is a subdivision to measure, so it has no effect\n * here — this entry point scores per-beat accents alone.\n */\n compoundSubdivisionThreshold?: number;\n}\n\n/**\n * Estimate meter over a caller-supplied beat series.\n *\n * @param request - Beat series plus optional scoring configuration\n * @returns The selected signature, its downbeat phase and grouping, and the\n * scored candidates\n *\n * @remarks\n * Scores only the per-beat strengths, so no audio and no frame-level onset\n * envelope is needed: an arbitrary span of an existing analysis can be scored\n * without re-running it. Pass `beatObservations.onsetStrength` rather than\n * `beats[].strength` — see {@link EstimateMeterRequest.beatStrengths}.\n *\n * The result carries `grouping` alongside the numerator: how the bar divides\n * into accent groups of two and three beats, so a seven comes back as `[3, 2,\n * 2]` or `[2, 2, 3]` rather than as a bare seven.\n *\n * Check `searched` before reading anything as a detection: a series too short\n * to score any candidate reports a fixed fallback instead, and `candidateScores`\n * grows with the square root of how many beats were scored, so scores from\n * spans of different lengths are not directly comparable.\n */\nexport function estimateMeter(request: EstimateMeterRequest): MeterEstimate {\n return requireModule().estimateMeter(request.beatTimes, request.beatStrengths, request);\n}\n\nexport function analyzeImpulseResponse(request: AnalyzeImpulseResponseRequest): AcousticResult;\nexport function analyzeImpulseResponse(\n samples: Float32Array,\n sampleRate?: number,\n nOctaveBands?: number,\n minDecayDb?: number,\n): AcousticResult;\nexport function analyzeImpulseResponse(\n samples: Float32Array | AnalyzeImpulseResponseRequest,\n sampleRate = 48000,\n nOctaveBands = 6,\n minDecayDb?: number,\n): AcousticResult {\n const request =\n samples instanceof Float32Array ? { samples, sampleRate, nOctaveBands, minDecayDb } : samples;\n // Only `undefined` takes the default. `null` falls through to\n // assertFiniteScalar, which refuses it with the same wording as any other\n // non-finite value -- Number.isFinite(null) is false, so the case needs no\n // branch of its own, and the one that was here answered it with a different\n // error class than the check three lines down.\n const resolvedMinDecayDb = request.minDecayDb === undefined ? 30.0 : request.minDecayDb;\n assertFiniteScalar('analyzeImpulseResponse', resolvedMinDecayDb, 'minDecayDb');\n if (resolvedMinDecayDb <= 0) {\n throw new RangeError('analyzeImpulseResponse: minDecayDb must be greater than zero');\n }\n validateAnalysisInput(\n 'analyzeImpulseResponse',\n request.samples,\n request.sampleRate ?? 48000,\n request,\n );\n const result: WasmAcousticResult = requireModule().analyzeImpulseResponseEx(\n request.samples,\n request.sampleRate ?? 48000,\n request.nOctaveBands ?? 6,\n resolvedMinDecayDb,\n );\n return result;\n}\n\nexport function detectAcoustic(request: DetectAcousticRequest): AcousticResult;\nexport function detectAcoustic(\n samples: Float32Array,\n sampleRate?: number,\n options?: AcousticOptions,\n): AcousticResult;\nexport function detectAcoustic(\n samples: Float32Array | DetectAcousticRequest,\n sampleRate = 48000,\n options: AcousticOptions = {},\n): AcousticResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('detectAcoustic', request.samples, request.sampleRate ?? 48000, request);\n const result: WasmAcousticResult = requireModule().detectAcoustic(\n request.samples,\n request.sampleRate ?? 48000,\n request.nOctaveBands ?? 6,\n request.nThirdOctaveSubbands ?? 24,\n request.minDecayDb ?? 30.0,\n request.noiseFloorMarginDb ?? 10.0,\n );\n return result;\n}\n\n/**\n * Synthesize a room impulse response from shoebox geometry. `hasError` is true\n * when the source/listener falls outside the room (the RIR is then empty).\n */\nexport function synthesizeRir(options: RirSynthOptions = {}): RirResult {\n const module = requireModule();\n if (typeof module.synthesizeRir !== 'function') {\n throw new Error('libsonare was built without acoustic-simulation support');\n }\n return module.synthesizeRir(options);\n}\n\n/**\n * Estimate an equivalent room (volume/dimensions/absorption/DRR) from a\n * recording or impulse response.\n */\nexport function estimateRoom(request: EstimateRoomRequest): RoomEstimateResult;\nexport function estimateRoom(\n samples: Float32Array,\n sampleRate?: number,\n options?: RoomEstimateOptions,\n): RoomEstimateResult;\nexport function estimateRoom(\n samples: Float32Array | EstimateRoomRequest,\n sampleRate = 48000,\n options: RoomEstimateOptions = {},\n): RoomEstimateResult {\n const module = requireModule();\n if (typeof module.estimateRoom !== 'function') {\n throw new Error('libsonare was built without acoustic-simulation support');\n }\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('estimateRoom', request.samples, request.sampleRate ?? 48000, request);\n return module.estimateRoom(request.samples, request.sampleRate ?? 48000, request);\n}\n\n/**\n * Morph a recording's reverberation toward a target room (creative FX, not\n * dereverberation).\n *\n * Returns the morphed samples in `audio` (input length plus the target room's\n * reverb tail) alongside the target-room synthesis's own `diagnostics`, which\n * report a room other than the one requested — see {@link RoomMorphResult}.\n */\nexport function roomMorph(request: RoomMorphRequest): RoomMorphResult;\nexport function roomMorph(\n samples: Float32Array,\n sampleRate: number,\n options?: RoomMorphOptions,\n): RoomMorphResult;\nexport function roomMorph(\n samples: Float32Array | RoomMorphRequest,\n sampleRate?: number,\n options: RoomMorphOptions = {},\n): RoomMorphResult {\n const module = requireModule();\n if (typeof module.roomMorph !== 'function') {\n throw new Error('libsonare was built without acoustic-simulation support');\n }\n const request =\n samples instanceof Float32Array\n ? { samples, sampleRate: sampleRate as number, ...options }\n : samples;\n validateAnalysisInput('roomMorph', request.samples, request.sampleRate, request);\n return module.roomMorph(request.samples, request.sampleRate, request);\n}\n\n/**\n * Perform complete music analysis with progress reporting.\n *\n * @param samples - Audio samples (mono, float32)\n * @param sampleRate - Sample rate in Hz (default: 22050)\n * @param onProgress - Progress callback (progress: 0-1, stage: string)\n * @returns Complete analysis result\n */\nexport function analyzeWithProgress(request: AnalyzeWithProgressRequest): AnalysisResult;\nexport function analyzeWithProgress(\n samples: Float32Array,\n sampleRate: number | undefined,\n onProgress: ProgressCallback,\n options?: MusicAnalyzeOptions,\n): AnalysisResult;\nexport function analyzeWithProgress(\n samples: Float32Array | AnalyzeWithProgressRequest,\n sampleRate = 22050,\n onProgress?: ProgressCallback,\n options?: MusicAnalyzeOptions,\n): AnalysisResult {\n const request: AnalyzeWithProgressRequest =\n samples instanceof Float32Array\n ? { samples, sampleRate, onProgress: onProgress as ProgressCallback, options }\n : samples;\n validateAnalysisInput(\n 'analyzeWithProgress',\n request.samples,\n request.sampleRate ?? 22050,\n request,\n );\n // The module reads options with the same reader analyze uses.\n const result = requireModule().analyzeWithProgress(\n request.samples,\n request.sampleRate ?? 22050,\n request.options ?? {},\n request.onProgress ?? (() => {}),\n request.cancel ?? (() => false),\n );\n return convertAnalysisResult(result);\n}\n\nexport interface BpmCandidate {\n bpm: number;\n confidence: number;\n}\n\nexport interface BpmAnalysisResult {\n bpm: number;\n confidence: number;\n candidates: BpmCandidate[];\n autocorrelation: Float32Array;\n tempogram: Float32Array;\n}\n\nexport interface RhythmAnalysisResult {\n timeSignature: { numerator: number; denominator: number; confidence: number };\n syncopation: number;\n grooveType: string;\n patternRegularity: number;\n tempoStability: number;\n /**\n * The beat tracker's own tempo, refined from the local beat period. It is a\n * third figure rather than either tempo entry point's: measured against\n * synthesized click trains it differs from both at every sample rate, and\n * lands closer to the known tempo than either. Analysed at the sample rate\n * you pass, so `nFft` and `hopLength` are in samples of your buffer.\n */\n bpm: number;\n beatIntervals: Float32Array;\n}\n\n/**\n * Dynamics metrics returned by {@link analyzeDynamics}.\n *\n * The Node package declares the same shape under the same name; the two are\n * pinned to one field list by `tests/conformance/shared_type_shapes.json`.\n */\nexport interface DynamicsResult {\n dynamicRangeDb: number;\n peakDb: number;\n rmsDb: number;\n crestFactor: number;\n loudnessRangeDb: number;\n isCompressed: boolean;\n /** Loudness curve timestamps (seconds), parallel to {@link loudnessRmsDb}. */\n loudnessTimes: Float32Array;\n /** Loudness curve RMS values (dB), parallel to {@link loudnessTimes}. */\n loudnessRmsDb: Float32Array;\n}\n\n/**\n * @deprecated Use {@link DynamicsResult}. Retained so code written against the\n * WASM-only spelling keeps compiling; the Node package exports the same alias.\n */\nexport type DynamicsAnalysisResult = DynamicsResult;\n\n/** Timbre metrics for one analysis window. Entries are ordered by time in `timbreOverTime`. */\nexport interface TimbreFrame {\n brightness: number;\n warmth: number;\n density: number;\n roughness: number;\n complexity: number;\n}\n\nexport interface TimbreAnalysisResult extends TimbreFrame {\n spectralCentroid: Float32Array;\n spectralFlatness: Float32Array;\n spectralRolloff: Float32Array;\n /** Time-varying timbre metrics, one entry per analysis window. */\n timbreOverTime: TimbreFrame[];\n}\n\n/**\n * Detailed BPM analysis (BPM, confidence, alternate candidates, autocorrelation,\n * tempogram). Matches the Node `analyzeBpm` / Python `analyze_bpm` surface.\n */\nexport function analyzeBpm(request: AnalyzeBpmRequest): BpmAnalysisResult;\nexport function analyzeBpm(\n samples: Float32Array,\n sampleRate?: number,\n options?: AnalyzeBpmOptions,\n): BpmAnalysisResult;\nexport function analyzeBpm(\n samples: Float32Array | AnalyzeBpmRequest,\n sampleRate = 22050,\n options: AnalyzeBpmOptions = {},\n): BpmAnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyzeBpm', request.samples, request.sampleRate ?? 22050, request);\n assertNonNegativeInteger('analyzeBpm', request.maxCandidates ?? 5, 'maxCandidates');\n return requireModule().analyzeBpm(\n request.samples,\n request.sampleRate ?? 22050,\n request.bpmMin ?? 30.0,\n request.bpmMax ?? 300.0,\n request.startBpm ?? 120.0,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n request.maxCandidates ?? 5,\n );\n}\n\n/**\n * Detailed rhythm analysis (time signature, groove, syncopation, beat intervals).\n */\nexport function analyzeRhythm(request: AnalyzeRhythmRequest): RhythmAnalysisResult;\nexport function analyzeRhythm(\n samples: Float32Array,\n sampleRate?: number,\n options?: AnalyzeRhythmOptions,\n): RhythmAnalysisResult;\nexport function analyzeRhythm(\n samples: Float32Array | AnalyzeRhythmRequest,\n sampleRate = 22050,\n options: AnalyzeRhythmOptions = {},\n): RhythmAnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyzeRhythm', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().analyzeRhythm(\n request.samples,\n request.sampleRate ?? 22050,\n request.bpmMin ?? 60.0,\n request.bpmMax ?? 200.0,\n request.startBpm ?? 120.0,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n );\n}\n\n/**\n * Dynamics analysis (RMS, peak, crest factor, LRA, loudness curve).\n */\nexport function analyzeDynamics(request: AnalyzeDynamicsRequest): DynamicsResult;\nexport function analyzeDynamics(\n samples: Float32Array,\n sampleRate?: number,\n options?: AnalyzeDynamicsOptions,\n): DynamicsResult;\nexport function analyzeDynamics(\n samples: Float32Array | AnalyzeDynamicsRequest,\n sampleRate = 22050,\n options: AnalyzeDynamicsOptions = {},\n): DynamicsResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyzeDynamics', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().analyzeDynamics(\n request.samples,\n request.sampleRate ?? 22050,\n request.windowSec ?? 0.4,\n request.hopLength ?? 512,\n request.compressionThreshold ?? 6.0,\n );\n}\n\n/**\n * Timbre analysis (brightness/warmth/density/roughness/complexity plus spectral\n * features and per-window timbre frames).\n */\nexport function analyzeTimbre(request: AnalyzeTimbreRequest): TimbreAnalysisResult;\nexport function analyzeTimbre(\n samples: Float32Array,\n sampleRate?: number,\n options?: AnalyzeTimbreOptions,\n): TimbreAnalysisResult;\nexport function analyzeTimbre(\n samples: Float32Array | AnalyzeTimbreRequest,\n sampleRate = 22050,\n options: AnalyzeTimbreOptions = {},\n): TimbreAnalysisResult {\n const request = samples instanceof Float32Array ? { samples, sampleRate, ...options } : samples;\n validateAnalysisInput('analyzeTimbre', request.samples, request.sampleRate ?? 22050, request);\n return requireModule().analyzeTimbre(\n request.samples,\n request.sampleRate ?? 22050,\n request.nFft ?? 2048,\n request.hopLength ?? 512,\n request.nMels ?? 128,\n request.nMfcc ?? 13,\n request.windowSec ?? 0.5,\n );\n}\n\n/**\n * Whether this WASM build was compiled with FFmpeg support. Mirrors Node /\n * Python `hasFfmpegSupport`. In the published WASM binding this currently\n * always returns `false` (FFmpeg is not bundled into the .wasm), but the API\n * exists so caller code can branch on capabilities portably.\n */\nexport function hasFfmpegSupport(): boolean {\n return requireModule().hasFfmpegSupport();\n}\n","/**\n * sonare - Audio Analysis Library\n *\n * @example\n * ```typescript\n * import { init, detectBpm, detectKey, analyze } from '@libraz/libsonare';\n *\n * await init();\n *\n * // Detect BPM from audio samples\n * const bpm = detectBpm(samples, sampleRate);\n *\n * // Detect musical key\n * const key = detectKey(samples, sampleRate);\n *\n * // Full analysis\n * const result = analyze(samples, sampleRate);\n * ```\n */\n\nimport { setSonareModule } from './module_state';\nimport type {\n CapabilityCatalog,\n RealtimeVoiceChangerPodConfig,\n SonareCapabilities,\n VoicePresetId,\n} from './public_types';\nimport type {\n SonareModule,\n WasmDecomposeResult,\n WasmHpssWithResidualResult,\n WasmMatrix2dResult,\n} from './sonare.js';\n\nexport { alignTakeToReference } from './align_take';\nexport type { BrowserAudioDecodeOptions } from './audio';\nexport { Audio } from './audio';\nexport type {\n ClipPageStreamerEngine,\n ClipPageStreamerOptions,\n ClipPageStreamerRequest,\n ClipPageStreamSource,\n OpfsClipStream,\n OpfsClipStreamOptions,\n WorkletOpfsClipStreamHost,\n} from './clip_page_streamer';\nexport { attachOpfsClipStream, ClipPageStreamer } from './clip_page_streamer';\nexport type {\n CompressorDetector,\n CompressorOptions,\n DeclickOptions,\n DeclipOptions,\n DecrackleMode,\n DecrackleOptions,\n DehumMode,\n DehumOptions,\n DenoiseClassicalMode,\n DenoiseClassicalNoiseEstimator,\n DenoiseClassicalOptions,\n DereverbClassicalOptions,\n DynamicsProcessorResult,\n GateOptions,\n MasteringAbMatchLoudnessRequest,\n MasteringAmpPresetCatalogEntry,\n MasteringAssistantParamsRequest,\n MasteringAssistantStereoParamsRequest,\n MasteringChannelPolicy,\n MasteringDynamicsCompressorRequest,\n MasteringDynamicsGateRequest,\n MasteringDynamicsTransientShaperRequest,\n MasteringInsertParamChoice,\n MasteringInsertParamInfo,\n MasteringInsertSlot,\n MasteringInsertTiming,\n MasteringPairAnalyzeRequest,\n MasteringPairProcessRequest,\n MasteringProcessorCatalogEntry,\n MasteringProcessorCategory,\n MasteringProcessRequest,\n MasteringProcessStereoRequest,\n MasteringRealtimeCost,\n MasteringRepairDeclickRequest,\n MasteringRepairDeclickStereoRequest,\n MasteringRepairDeclipRequest,\n MasteringRepairDeclipStereoRequest,\n MasteringRepairDecrackleRequest,\n MasteringRepairDecrackleStereoRequest,\n MasteringRepairDehumRequest,\n MasteringRepairDehumStereoRequest,\n MasteringRepairDenoiseClassicalLinkedRequest,\n MasteringRepairDenoiseClassicalRequest,\n MasteringRepairDenoiseClassicalStereoRequest,\n MasteringRepairDereverbClassicalLinkedRequest,\n MasteringRepairDereverbClassicalRequest,\n MasteringRepairDereverbClassicalStereoRequest,\n MasteringRepairDereverbConfigForRoomRequest,\n MasteringRepairDetectClicksRequest,\n MasteringRepairDetectClippingRequest,\n MasteringRepairDetectCrackleRequest,\n MasteringRepairDetectHumRequest,\n MasteringRepairDetectNoiseFloorRequest,\n MasteringRepairDetectReverbRequest,\n MasteringRepairDetectTrimRangeRequest,\n MasteringRepairDetectTrimRangeStereoRequest,\n MasteringRepairNoiseBandBinsRequest,\n MasteringRepairTrimSilenceRequest,\n MasteringRepairTrimSilenceStereoRequest,\n MasteringSamplesParamsRequest,\n MasteringStereoAnalyzeRequest,\n MasteringStereoParamsRequest,\n MasteringStreamingPreviewRequest,\n MasteringStreamingPreviewStereoRequest,\n MixStereoRequest,\n TransientShaperOptions,\n TrimSilenceMode,\n TrimSilenceOptions,\n VoiceChangeOptions,\n VoiceChangeRealtimeOptions,\n VoiceChangeRealtimeRequest,\n VoiceChangeRequest,\n} from './effects_mastering';\nexport {\n assignNoteTargets,\n decomposeNotePitch,\n extractNotes,\n extractPercussiveEvents,\n harmonic,\n hpss,\n masterAudio,\n masterAudioStereo,\n masterAudioStereoWithProgress,\n masterAudioWithProgress,\n mastering,\n masteringAbMatchLoudness,\n masteringAmpPresetCatalog,\n masteringAssistantSuggest,\n masteringAssistantSuggestChain,\n masteringAssistantSuggestChainStereo,\n masteringAssistantSuggestStereo,\n masteringAudioProfile,\n masteringAudioProfileStereo,\n masteringChain,\n masteringChainStereo,\n masteringChainStereoWithProgress,\n masteringChainWithProgress,\n masteringDynamicsCompressor,\n masteringDynamicsGate,\n masteringDynamicsTransientShaper,\n masteringInsertNames,\n masteringInsertParamInfo,\n masteringInsertParamNames,\n masteringInsertTiming,\n masteringPairAnalysisNames,\n masteringPairAnalyze,\n masteringPairProcess,\n masteringPairProcessorNames,\n masteringPlatformNames,\n masteringPresetNames,\n masteringPresetParams,\n masteringProcess,\n masteringProcessorCatalog,\n masteringProcessorNames,\n masteringProcessStereo,\n masteringRepairDeclick,\n masteringRepairDeclickStereo,\n masteringRepairDeclip,\n masteringRepairDeclipStereo,\n masteringRepairDecrackle,\n masteringRepairDecrackleStereo,\n masteringRepairDehum,\n masteringRepairDehumStereo,\n masteringRepairDenoiseClassical,\n masteringRepairDenoiseClassicalLinked,\n masteringRepairDenoiseClassicalStereo,\n masteringRepairDereverbClassical,\n masteringRepairDereverbClassicalLinked,\n masteringRepairDereverbClassicalStereo,\n masteringRepairDereverbConfigForRoom,\n masteringRepairDetectClicks,\n masteringRepairDetectClipping,\n masteringRepairDetectCrackle,\n masteringRepairDetectHum,\n masteringRepairDetectNoiseFloor,\n masteringRepairDetectReverb,\n masteringRepairDetectTrimRange,\n masteringRepairDetectTrimRangeStereo,\n masteringRepairNoiseBandBins,\n masteringRepairTrimSilence,\n masteringRepairTrimSilenceStereo,\n masteringStereoAnalysisNames,\n masteringStereoAnalyze,\n masteringStreamingPreview,\n masteringStreamingPreviewStereo,\n mergeNotes,\n mixingScenePresetJson,\n mixingScenePresetNames,\n mixStereo,\n normalize,\n normalizeStereo,\n noteMove,\n noteStretch,\n noteTargetsFromSmf,\n percussive,\n pitchCorrectTimevarying,\n pitchCorrectToMidi,\n pitchCorrectToMidiTimevarying,\n pitchShift,\n renderNotes,\n renderPercussiveEvents,\n spectralEdit,\n splitNote,\n timeStretch,\n voiceChange,\n voiceChangeRealtime,\n} from './effects_mastering';\nexport type {\n AssignNoteTargetsRequest,\n DecomposeNotePitchRequest,\n ExtractNotesRequest,\n MergeNotesRequest,\n NoteMoveRequest,\n NoteSetRequest,\n NoteStretchRequest,\n NoteTargetsFromSmfRequest,\n RenderNotesRequest,\n SplitNoteRequest,\n} from './effects_note_ops';\nexport type {\n ExtractPercussiveEventsRequest,\n PercussiveSeparationOptions,\n RenderPercussiveEventsRequest,\n} from './effects_percussive';\nexport type { HarmonicRequest, HpssRequest, PercussiveRequest } from './effects_separation';\nexport type { SpectralEditRequest } from './effects_spectral';\nexport type {\n PitchCorrectTimevaryingRequest,\n PitchCorrectToMidiRequest,\n PitchCorrectToMidiTimevaryingRequest,\n PitchShiftRequest,\n TimeStretchRequest,\n} from './effects_timepitch';\nexport { ErrorCode, isSonareError, SonareError } from './errors';\nexport type {\n ChirpRequest,\n ClicksRequest,\n CyclicTempogramRequest,\n DbConversionRequest,\n EmphasisRequest,\n FixFramesRequest,\n FixLengthRequest,\n FrameSignalRequest,\n OnsetBacktrackRequest,\n PadCenterRequest,\n PcenRequest,\n PeakPickRequest,\n PlpRequest,\n SilenceCommonReport,\n SilenceRequest,\n SplitSilenceCommonRequest,\n SplitSilenceCommonWithReportResult,\n TempogramRequest,\n ToneRequest,\n TonnetzRequest,\n VectorNormalizeRequest,\n} from './feature_core';\nexport type {\n DecomposeRequest,\n DecomposeStemsLinkedRequest,\n DecomposeStemsLinkedResult,\n DecomposeStemsRequest,\n DecomposeStemsResult,\n DecomposeWithInitRequest,\n HpssWithResidualRequest,\n NnFilterRequest,\n RemixRequest,\n SegmentAgglomerativeRequest,\n SegmentCrossSimilarityRequest,\n SegmentLagToRecurrenceRequest,\n SegmentPathEnhanceRequest,\n SegmentRecurrenceMatrixRequest,\n SegmentRecurrenceToLagRequest,\n SegmentSubsegmentRequest,\n} from './feature_decompose';\nexport type {\n GriffinLimRequest,\n MelToAudioRequest,\n MelToStftRequest,\n MfccToAudioRequest,\n MfccToMelRequest,\n PhaseVocoderRequest,\n} from './feature_inverse';\nexport type {\n Ebur128LoudnessRangeRequest,\n LufsInterleavedRequest,\n LufsSeriesInterleavedRequest,\n} from './feature_loudness';\nexport type {\n AnalyzeMelodyRequest,\n AnalyzeSectionsRequest,\n CqtRequest,\n CqtToAudioRequest,\n DetectBoundariesRequest,\n FourierTempogramRequest,\n LufsRequest,\n MelodyOptions,\n NnlsChromaRequest,\n OnsetEnvelopeRequest,\n OnsetStrengthMultiRequest,\n TempogramRatioRequest,\n VqtRequest,\n VqtToAudioRequest,\n} from './feature_music';\nexport type {\n EstimateTuningRequest,\n NoteSegmentsRequest,\n PiptrackRequest,\n PitchPyinRequest,\n PitchTuningRequest,\n PitchYinRequest,\n} from './feature_pitch';\nexport type { ResampleRequest } from './feature_resample';\nexport type {\n PolyFeaturesRequest,\n SpectralContrastRequest,\n SpectralFrameRequest,\n SpectralRolloffRequest,\n ZeroCrossingRateRequest,\n ZeroCrossingsRequest,\n} from './feature_spectral';\nexport type {\n BassChromaSpectrogramRequest,\n ChromaSpectrogramRequest,\n MelDeltaRequest,\n MelSpectrogramRequest,\n MfccRequest,\n ReassignedSpectrogramRequest,\n SpectrogramRequest,\n TrimRequest,\n} from './feature_spectrogram';\nexport {\n amplitudeToDb,\n analyzeMelody,\n analyzeSections,\n bassChroma,\n chirp,\n chroma,\n chromaCens,\n chromaCqt,\n clicks,\n cqt,\n cqtToAudio,\n cyclicTempogram,\n dbToAmplitude,\n dbToPower,\n decompose,\n decomposeStems,\n decomposeStemsLinked,\n decomposeWithInit,\n deemphasis,\n detectBoundaries,\n ebur128LoudnessRange,\n estimateTuning,\n fixFrames,\n fixLength,\n fourierTempogram,\n frameSignal,\n framesToSamples,\n framesToTime,\n griffinLim,\n hpssWithResidual,\n hybridCqt,\n hzToMel,\n hzToMidi,\n hzToNote,\n lufs,\n lufsInterleaved,\n lufsSeriesInterleaved,\n melDelta,\n melSpectrogram,\n melToAudio,\n melToHz,\n melToStft,\n mfcc,\n mfccToAudio,\n mfccToMel,\n midiToHz,\n momentaryLufs,\n nnFilter,\n nnlsChroma,\n noteSegments,\n noteToHz,\n onsetBacktrack,\n onsetEnvelope,\n onsetStrengthMulti,\n padCenter,\n pcen,\n peakPick,\n phaseVocoder,\n piptrack,\n pitchPyin,\n pitchTuning,\n pitchYin,\n plp,\n polyFeatures,\n powerToDb,\n preemphasis,\n pseudoCqt,\n reassignedSpectrogram,\n remix,\n remixAlignedIntervals,\n resample,\n rmsEnergy,\n samplesToFrames,\n segmentAgglomerative,\n segmentCrossSimilarity,\n segmentLagToRecurrence,\n segmentPathEnhance,\n segmentRecurrenceMatrix,\n segmentRecurrenceToLag,\n segmentSubsegment,\n shortTermLufs,\n spectralBandwidth,\n spectralCentroid,\n spectralContrast,\n spectralFlatness,\n spectralFlux,\n spectralRolloff,\n splitSilence,\n splitSilenceCommon,\n splitSilenceCommonWithReport,\n stft,\n stftDb,\n tempogram,\n tempogramRatio,\n timeToFrames,\n tone,\n tonnetz,\n trim,\n trimSilence,\n vectorNormalize,\n vqt,\n vqtToAudio,\n zeroCrossingRate,\n zeroCrossings,\n} from './features';\nexport type { BindMicrophoneInputOptions, MicrophoneInputBinding } from './live_audio';\nexport { bindMicrophoneInput } from './live_audio';\nexport type {\n MasterAudioRequest,\n MasterAudioStereoRequest,\n MasteringChainRequest,\n MasteringChainStereoRequest,\n NormalizeMode,\n NormalizeRequest,\n NormalizeStereoRequest,\n NormalizeStereoResult,\n} from './mastering_chain';\nexport type { MasteringRequest } from './mastering_core';\nexport type {\n ClippingRegion,\n ClippingReport,\n DynamicRangeReport,\n MeteringDetectClippingOptions,\n MeteringDetectClippingRequest,\n MeteringDynamicRangeOptions,\n MeteringDynamicRangeRequest,\n MeteringSamplesRequest,\n MeteringSilenceRatioRequest,\n MeteringSpectrumFrameRequest,\n MeteringSpectrumRequest,\n MeteringStereoDecimatedRequest,\n MeteringStereoRequest,\n MeteringTruePeakRequest,\n PhaseScopeReport,\n SpectrumOptions,\n SpectrumReport,\n VectorscopeReport,\n WaveformPeakPyramidOptions,\n WaveformPeakPyramidRequest,\n WaveformPeaksOptions,\n WaveformPeaksReport,\n WaveformPeaksRequest,\n} from './metering';\nexport {\n meteringCrestFactorDb,\n meteringCrestFactorDbStereo,\n meteringDcOffset,\n meteringDetectClipping,\n meteringDynamicRange,\n meteringPeakDb,\n meteringPhaseScope,\n meteringPhaseScopeDecimated,\n meteringRmsDb,\n meteringSilenceRatio,\n meteringSpectrum,\n meteringSpectrumFrame,\n meteringStereoCorrelation,\n meteringStereoWidth,\n meteringTruePeakDb,\n meteringVectorscope,\n meteringVectorscopeDecimated,\n waveformPeakPyramid,\n waveformPeaks,\n} from './metering';\nexport type { SuggestMixSceneRequest } from './mixing_assistant';\nexport {\n mixSourceClassFromName,\n mixSourceClassNames,\n suggestMixScene,\n suggestMixSceneJson,\n} from './mixing_assistant';\nexport type {\n OpfsClipPageProviderBinding,\n OpfsClipPageProviderOptions,\n} from './opfs_clip_pages';\nexport {\n createOpfsClipPageProvider,\n createOpfsClipPageWorker,\n opfsClipPageWorkerSource,\n} from './opfs_clip_pages';\nexport {\n HrtfSet,\n PlaybackLoudnessMeter,\n PlaybackRenderer,\n renderPlayback,\n} from './playback_renderer';\nexport type { AnalyzePolyphonicRequest } from './polyphony';\nexport { analyzePolyphonic, PolyphonicAnalysis } from './polyphony';\nexport type {\n AlignTakeToReferenceRequest,\n AlignTakeToReferenceResult,\n Articulation,\n BuiltinSynthBinding,\n BuiltinSynthConfig,\n BuiltinSynthWaveform,\n ControllerAxis,\n ControllerBinding,\n ControllerInput,\n ExternalSeparatedStem,\n ExternalSeparatedStemImportRequest,\n ExternalSeparatedStemImportResult,\n MidiCcLearnOptions,\n MpeDimension,\n NoteTracking,\n ProjectAssistSidecar,\n ProjectAssistSidecarInput,\n ProjectAutomationCurve,\n ProjectAutomationLaneDesc,\n ProjectAutomationPoint,\n ProjectAutomationTargetKind,\n ProjectBounceOptions,\n ProjectChordSymbol,\n ProjectClip,\n ProjectClipCompSegment,\n ProjectClipDesc,\n ProjectClipFade,\n ProjectClipTake,\n ProjectCompileResult,\n ProjectFadeCurve,\n ProjectKeySegment,\n ProjectLoopMode,\n ProjectLoopRecordingDesc,\n ProjectLoopRecordingResult,\n ProjectMarker,\n ProjectMidiClipResult,\n ProjectMidiEvent,\n ProjectMidiFxBakeRequest,\n ProjectMidiFxBakeResult,\n ProjectMidiFxPreviewRequest,\n ProjectNotePairValidation,\n ProjectSource,\n ProjectTempoCandidate,\n ProjectTempoOptions,\n ProjectTempoSegment,\n ProjectTimeSignatureSegment,\n ProjectTrack,\n ProjectTrackDesc,\n ProjectTrackKind,\n ProjectTranscribeRequest,\n ProjectWarpAnchor,\n ProjectWarpMapDesc,\n SampleDesc,\n SampleDescLoopMode,\n SampleKeyTrack,\n SampleLoopMode,\n SampleZoneDesc,\n Sf2InstrumentConfig,\n Sf2ProgramStatus,\n SourceBackend,\n SynthBodyType,\n SynthEngineMode,\n SynthEnumTables,\n SynthFilterModel,\n SynthFilterOutput,\n SynthModDestination,\n SynthModRouting,\n SynthModSource,\n SynthOscWaveform,\n SynthPatch,\n SynthRetrigger,\n TakeAlignment,\n TranscribeOptions,\n TranscribeResult,\n} from './project';\nexport {\n ARTICULATIONS,\n AutomationTargetKind,\n BUILTIN_SYNTH_WAVEFORMS,\n CONTROLLER_AXES,\n CONTROLLER_INPUTS,\n controllerProfileNames,\n EXPECTED_PROJECT_ABI_VERSION,\n MarkerKind,\n MPE_DIMENSIONS,\n NOTE_TRACKINGS,\n PROJECT_AUTOMATION_TARGET_OPAQUE,\n PROJECT_AUTOMATION_TARGET_TRACK_FADER_DB,\n PROJECT_AUTOMATION_TARGET_TRACK_PAN,\n Project,\n projectAbiVersion,\n SAMPLE_KEY_TRACKS,\n SAMPLE_LOOP_MODES,\n SampleBank,\n SYNTH_BODY_TYPES,\n SYNTH_ENGINE_MODES,\n SYNTH_FILTER_MODELS,\n SYNTH_FILTER_OUTPUTS,\n SYNTH_MOD_DESTINATIONS,\n SYNTH_MOD_SOURCES,\n SYNTH_OSC_WAVEFORMS,\n SYNTH_RETRIGGERS,\n synthEnumTables,\n synthGsDrumKitIsVoicedApart,\n synthGsDrumKitName,\n synthGsVariationIsVoicedApart,\n synthPresetNames,\n synthPresetPatch,\n} from './project';\nexport type {\n AcousticOptions,\n AcousticResult,\n AnalysisChord,\n AnalysisResult,\n AnalyzeBpmOptions,\n AnalyzeDynamicsOptions,\n AnalyzeRhythmOptions,\n AnalyzeSectionsOptions,\n AnalyzeTimbreOptions,\n AutomationCurve,\n Beat,\n Boundary,\n BoundaryOptions,\n BoundaryResult,\n BpmHypothesis,\n CapabilityCatalog,\n CapabilityCatalogMasteringPreset,\n CapabilityCatalogParameter,\n CapabilityCatalogPresets,\n CapabilityCatalogProcessor,\n Chord,\n ChordAnalysisResult,\n ChordDetectionOptions,\n ChromaResult,\n ClickDetection,\n ClipDetection,\n CqtResult,\n CrackleDetection,\n DeclickReport,\n DeclipReport,\n DecrackleReport,\n DehumReport,\n DenoiseReport,\n DereverbReport,\n Dynamics,\n EqBand,\n EqBandPhase,\n EqBandType,\n EqCoeffMode,\n EqMatchOptions,\n EqSpectrumSnapshot,\n EqStereoPlacement,\n GoniometerPoint,\n HpssResult,\n HumDetection,\n Key,\n KeyCandidate,\n KeyDetectionOptions,\n KeyProfileName,\n LoudnessMatchResult,\n LufsResult,\n LufsSeriesResult,\n MasteringAssistantParams,\n MasteringChainConfig,\n MasteringChainResult,\n MasteringChainStereoResult,\n MasteringLoudnessSummary,\n MasteringOptions,\n MasteringPreset,\n MasteringProcessorParams,\n MasteringRepairDeclickStereoResult,\n MasteringRepairDeclipStereoResult,\n MasteringRepairDecrackleStereoResult,\n MasteringRepairDehumStereoResult,\n MasteringRepairDenoiseClassicalLinkedResult,\n MasteringRepairDenoiseClassicalStereoResult,\n MasteringRepairDereverbClassicalLinkedResult,\n MasteringRepairDereverbClassicalStereoResult,\n MasteringRepairTrimSilenceStereoResult,\n MasteringReport,\n MasteringResult,\n MasteringStereoChainResult,\n MasteringStereoResult,\n MelodyPoint,\n MelodyResult,\n MelPowerResult,\n MelSpectrogramResult,\n MeterTap,\n MfccResult,\n MixAnalysisBand,\n MixAssistantMixProfile,\n MixAssistantOptions,\n MixAssistantResult,\n MixAssistantTrack,\n MixAssistantTrackProfile,\n MixBandDominance,\n MixBandOccupancy,\n MixCrowdedBand,\n MixerProcessResult,\n MixMeterSnapshot,\n MixMonoRisk,\n MixOptions,\n MixResult,\n MixSceneBus,\n MixSceneConnection,\n MixSceneDocument,\n MixSceneInsert,\n MixSceneSend,\n MixSceneStrip,\n MixSceneVcaGroup,\n MixTrackAlignment,\n NoiseDetection,\n NoteEdit,\n NoteEditInput,\n NoteExtractorOptions,\n NoteObject,\n NoteObjectInput,\n NoteSegment,\n NoteSetEntry,\n NoteStretchOptions,\n NoteTarget,\n NoteTargetAssignResult,\n NoteTargetUnmatchedPolicy,\n PairAnalysis,\n PairProcessor,\n PanLaw,\n PanLawInput,\n PanLawName,\n PanMode,\n PercussiveEvent,\n PercussiveEventEdit,\n PercussiveEventEditInput,\n PercussiveEventInput,\n PitchCorrectOptions,\n PitchDecompositionResult,\n PitchResult,\n PlaybackBassManagementConfig,\n PlaybackChannelRole,\n PlaybackDiagnostics,\n PlaybackHeadTrackingConfig,\n PlaybackInputConfig,\n PlaybackLoudnessConfig,\n PlaybackNightModeConfig,\n PlaybackOutputLimiterConfig,\n PlaybackRendererConfig,\n PlaybackRendererOptions,\n PlaybackRoomConfig,\n PlaybackSpeakerConfig,\n PlaybackStageLatency,\n PlaybackStageName,\n PlaybackTargetConfig,\n PlaybackUpmixConfig,\n PolyphonicAnalysisOptions,\n PolyphonicRenderOptions,\n RealtimeVoiceChangerConfigInput,\n RealtimeVoiceChangerPodConfig,\n RenderPlaybackRequest,\n RenderPlaybackResult,\n ReverbDetection,\n RhythmFeatures,\n RirDiagnostic,\n RirResult,\n RirSynthOptions,\n RoomEstimateOptions,\n RoomEstimateResult,\n RoomGeometryOptions,\n RoomMorphOptions,\n RoomMorphResult,\n Section,\n SegmentMatrix,\n SendTiming,\n SidechainSourceKind,\n SoloProcessor,\n SonareCapabilities,\n SpectralEditMode,\n SpectralEditOptions,\n SpectralEditWindow,\n SpectralRegionOp,\n StageGainReduction,\n StereoAnalysis,\n StftPowerResult,\n StftResult,\n StreamingEqualizerConfig,\n StreamingMasteringChainConfig,\n StreamingPlatform,\n StreamingRetuneConfig,\n TempogramMode,\n Timbre,\n TimeSignature,\n TrimRange,\n TrimReport,\n UmpWords,\n VoicedFlags,\n VoicePresetId,\n} from './public_types';\nexport {\n ChordQuality,\n KeyProfile,\n Mode,\n PitchClass,\n SectionType,\n} from './public_types';\nexport type {\n AnalyzeBpmRequest,\n AnalyzeDynamicsRequest,\n AnalyzeImpulseResponseRequest,\n AnalyzeRhythmRequest,\n AnalyzeTimbreRequest,\n AnalyzeWithProgressRequest,\n BpmAnalysisResult,\n BpmCandidate,\n ChordFunctionalAnalysisRequest,\n DetectAcousticRequest,\n DetectChordsRequest,\n DetectKeyRequest,\n DetectOnsetsRequest,\n DynamicsAnalysisResult,\n DynamicsResult,\n EstimateMeterRequest,\n EstimateRoomRequest,\n MusicAnalyzeRequest,\n RhythmAnalysisResult,\n RoomMorphRequest,\n SamplesRequest,\n TimbreAnalysisResult,\n TimbreFrame,\n} from './quick_analysis';\nexport {\n analyze,\n analyzeBpm,\n analyzeDynamics,\n analyzeImpulseResponse,\n analyzeRhythm,\n analyzeTimbre,\n analyzeWithProgress,\n chordFunctionalAnalysis,\n detectAcoustic,\n detectBeats,\n detectBpm,\n detectChords,\n detectDownbeats,\n detectKey,\n detectKeyCandidates,\n detectOnsets,\n estimateMeter,\n estimateRoom,\n hasFfmpegSupport,\n roomMorph,\n synthesizeRir,\n} from './quick_analysis';\nexport type {\n ClipPageRequest,\n EngineAutomationPoint,\n EngineBounceOptions,\n EngineBounceResult,\n EngineBus,\n EngineCapabilities,\n EngineCaptureSource,\n EngineCaptureStatus,\n EngineClip,\n EngineFreezeOptions,\n EngineFreezeResult,\n EngineGraphSpec,\n EngineMarker,\n EngineMeterTelemetry,\n EngineMeterTelemetryWide,\n EngineMetronomeConfig,\n EngineMidiClipSchedule,\n EngineMidiEvent,\n EngineParameterInfo,\n EngineScopeTelemetry,\n EngineTelemetry,\n EngineTempoSegment,\n EngineTimeSignatureSegment,\n EngineTrackLane,\n EngineTrackMonitorMode,\n EngineTrackSend,\n EngineTransportState,\n ExternalMidiEvent,\n MidiCcBindOptions,\n RenderOfflineRequest,\n TrackMonitorMode,\n} from './realtime_engine';\nexport {\n ClipPageProvider,\n EXPECTED_ENGINE_ABI_VERSION,\n engineCapabilities,\n RealtimeEngine,\n} from './realtime_engine';\nexport { scaleCorrectionSemitones, scalePitchClassEnabled, scaleQuantizeMidi } from './scale';\nexport type { ProgressCallback } from './sonare.js';\nexport { StreamAnalyzer, streamAnalyzerConfigDefaults } from './stream_analyzer';\nexport type {\n AnalyzerStats,\n BarChord,\n ChordChange,\n FrameBuffer,\n PatternScore,\n ProgressiveEstimate,\n StreamConfig,\n StreamConfigDefaults,\n StreamFramesI16,\n StreamFramesU8,\n StreamQuantizeConfig,\n} from './stream_types';\nexport type {\n MixerMeterSnapshot,\n MixerRealtimeBuffer,\n RealtimeVoiceChangerInterleavedBuffer,\n RealtimeVoiceChangerMonoBuffer,\n RealtimeVoiceChangerPlanarBuffer,\n StripMeteringOptions,\n} from './streaming_mixing';\nexport {\n Mixer,\n RealtimeVoiceChanger,\n realtimeVoiceChangerPresetJson,\n realtimeVoiceChangerPresetNames,\n StreamingEqualizer,\n StreamingMasteringChain,\n StreamingRetune,\n validateRealtimeVoiceChangerPresetJson,\n} from './streaming_mixing';\nexport type { TranscribeRequest } from './transcribe';\nexport { transcribe } from './transcribe';\nexport type { ValidateOptions } from './validation';\nexport type {\n BindWebMidiOptions,\n WebMidiBinding,\n WebMidiCcBinding,\n WebMidiInputInfo,\n} from './web_midi';\nexport { bindWebMidi, isWebMidiAvailable } from './web_midi';\nexport type {\n OfflineWorker,\n OfflineWorkerCallOptions,\n OfflineWorkerClientOptions,\n OfflineWorkerProgress,\n} from './worker_client';\nexport { OfflineWorkerClient, OfflineWorkerTask } from './worker_client';\n\n/** Row-major 2-D matrix as a flat buffer plus its dimensions. */\nexport type Matrix2dResult = WasmMatrix2dResult;\n/** NMF factor matrices { w, h } from {@link decompose}. */\nexport type DecomposeResult = WasmDecomposeResult;\n/** Harmonic / percussive / residual signals from {@link hpssWithResidual}. */\nexport type HpssWithResidualResult = WasmHpssWithResidualResult;\n\n// ============================================================================\n// Module State\n// ============================================================================\n\nlet module: SonareModule | null = null;\nlet initPromise: Promise<void> | null = null;\n\n// ============================================================================\n// Initialization\n// ============================================================================\n\n/**\n * Initialize the WASM module.\n * Must be called before using any analysis functions.\n *\n * @param options - Optional module configuration\n * @returns Promise that resolves when initialization is complete\n */\nexport async function init(options?: {\n locateFile?: (path: string, prefix: string) => string;\n wasmBinary?: ArrayBuffer | Uint8Array;\n moduleFactory?: (options?: {\n locateFile?: (path: string, prefix: string) => string;\n wasmBinary?: ArrayBuffer | Uint8Array;\n }) => Promise<SonareModule>;\n}): Promise<void> {\n if (module) {\n return;\n }\n\n if (initPromise) {\n return initPromise;\n }\n\n initPromise = (async () => {\n try {\n const createModule = options?.moduleFactory ?? (await import('./sonare.js')).default;\n module = await createModule(options);\n setSonareModule(module);\n } catch (error) {\n initPromise = null;\n throw error;\n }\n })();\n\n return initPromise;\n}\n\n/**\n * Check if the module is initialized.\n */\nexport function isInitialized(): boolean {\n return module !== null;\n}\n\n/**\n * Get the library version.\n */\nexport function version(): string {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.version();\n}\n\n/**\n * Return the capabilities of the loaded WASM build.\n *\n * This is synchronous and only describes the already-initialized module.\n */\nexport function capabilities(): SonareCapabilities {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.capabilities();\n}\n\n/** Return the initialized module's processors, parameters, and presets. */\nexport function capabilityCatalog(): CapabilityCatalog {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return JSON.parse(module.capabilityCatalog()) as CapabilityCatalog;\n}\n\n/**\n * Aggregate native ABI version: the per-subsystem ABI macros folded into one\n * 32-bit value. It bumps whenever any flat C POD layout changes, so callers can\n * detect an incompatible prebuilt binary. Matches the Node/Python `abiVersion()`.\n */\nexport function abiVersion(): number {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.abiVersion();\n}\n\nexport function engineAbiVersion(): number {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.engineAbiVersion();\n}\n\nexport function voiceChangerAbiVersion(): number {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.voiceChangerAbiVersion();\n}\n\n// Canonical ordinal order of the built-in voice-character presets, matching the\n// C ABI SonareVoiceCharacterPreset enum and SONARE_REALTIME_VOICE_CHANGER_PRESET_IDS.\nconst VOICE_PRESET_ORDINALS: readonly VoicePresetId[] = [\n 'neutral-monitor',\n 'bright-idol',\n 'soft-whisper',\n 'deep-narrator',\n 'robot-mascot',\n 'dark-villain',\n];\n\nfunction resolveVoicePresetOrdinal(preset: VoicePresetId | number): number {\n if (typeof preset === 'number') {\n if (!Number.isSafeInteger(preset) || preset < 0 || preset >= VOICE_PRESET_ORDINALS.length) {\n throw new RangeError(`Unknown voice-character preset ordinal: ${String(preset)}`);\n }\n return preset;\n }\n const ordinal = VOICE_PRESET_ORDINALS.indexOf(preset);\n if (ordinal < 0) {\n throw new Error(`Unknown voice character preset: ${preset}`);\n }\n return ordinal;\n}\n\n/**\n * Map a voice-character preset ordinal (or canonical id) to its canonical id\n * string (e.g. `'bright-idol'`). Unknown numeric ordinals return `null`;\n * unknown preset ids throw.\n */\nexport function voiceCharacterPresetId(preset: VoicePresetId | number): VoicePresetId | null {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n if (\n typeof preset === 'number' &&\n (!Number.isSafeInteger(preset) || preset < 0 || preset >= VOICE_PRESET_ORDINALS.length)\n ) {\n return null;\n }\n return module.voiceCharacterPresetId(resolveVoicePresetOrdinal(preset)) as VoicePresetId;\n}\n\n/**\n * Return the canonical (normalized) flat POD config for a built-in voice\n * preset, skipping the JSON round-trip. Accepts a canonical preset id or its\n * integer ordinal. Invalid ordinals throw.\n */\nexport function realtimeVoiceChangerPresetConfig(\n preset: VoicePresetId | number,\n): RealtimeVoiceChangerPodConfig {\n if (!module) {\n throw new Error('Module not initialized. Call init() first.');\n }\n return module.realtimeVoiceChangerPresetConfig(resolveVoicePresetOrdinal(preset));\n}\n\n// ============================================================================\n// Re-exports\n// ============================================================================\n\nexport { PitchClass as Pitch } from './public_types';\n","/**\n * Offline one-shot operations hosted inside a dedicated Web Worker.\n *\n * Only value-based calls are exposed here: analysis and preset mastering. Do\n * not add `Project`, `Mixer`, or realtime handles. Their native lifetime is\n * bound to one JavaScript realm, so moving them across a Worker boundary would\n * make ownership and `delete()` semantics unsound.\n */\n\nimport { ErrorCode, SonareError } from './errors';\nimport { init } from './index';\nimport type { MasterAudioRequest, MasterAudioStereoRequest } from './mastering_chain';\nimport { masterAudio, masterAudioStereo } from './mastering_chain';\nimport type {\n DetectChordsRequest,\n DetectKeyRequest,\n MusicAnalyzeRequest,\n SamplesRequest,\n} from './quick_analysis';\nimport { analyzeWithProgress, detectBpm, detectChords, detectKey } from './quick_analysis';\nimport type {\n OfflineWorkerErrorMessage,\n OfflineWorkerRequestMessage,\n OfflineWorkerResponseMessage,\n OfflineWorkerRunMessage,\n} from './worker_protocol';\n\nexport type { OfflineWorkerOperation } from './worker_protocol';\n\n/** Minimal endpoint shared by browser Workers and the Node worker-thread test bridge. */\nexport interface OfflineWorkerEndpoint {\n postMessage(message: OfflineWorkerResponseMessage, transfer?: Transferable[]): void;\n addEventListener(\n type: 'message',\n listener: (event: MessageEvent<OfflineWorkerRequestMessage>) => void,\n ): void;\n}\n\nfunction transferableBuffers(value: unknown, seen = new Set<object>()): Transferable[] {\n const buffers: Transferable[] = [];\n const seenBuffers = new Set<ArrayBuffer>();\n const visit = (item: unknown): void => {\n if (item === null || item === undefined || typeof item !== 'object') {\n return;\n }\n if (ArrayBuffer.isView(item)) {\n const buffer = item.buffer;\n if (buffer instanceof ArrayBuffer && !seenBuffers.has(buffer)) {\n seenBuffers.add(buffer);\n buffers.push(buffer);\n }\n return;\n }\n if (item instanceof ArrayBuffer) {\n if (!seenBuffers.has(item)) {\n seenBuffers.add(item);\n buffers.push(item);\n }\n return;\n }\n if (seen.has(item)) {\n return;\n }\n seen.add(item);\n if (Array.isArray(item)) {\n item.forEach(visit);\n return;\n }\n Object.values(item).forEach(visit);\n };\n visit(value);\n return buffers;\n}\n\nfunction errorMessage(error: unknown): OfflineWorkerErrorMessage['error'] {\n if (error instanceof SonareError) {\n return {\n name: error.name,\n message: error.message,\n code: error.code,\n codeName: error.codeName,\n };\n }\n if (error instanceof Error) {\n return { name: error.name, message: error.message };\n }\n return { name: 'Error', message: String(error) };\n}\n\nfunction cancelledError(): SonareError {\n return new SonareError(ErrorCode.Cancelled, 'Cancelled', 'Operation cancelled');\n}\n\n/**\n * Install the protocol on an endpoint. This export is intentionally useful to\n * the Node `worker_threads` test adapter; browsers install it automatically\n * when this module is loaded as a Worker entry point.\n */\nexport function installOfflineWorkerEndpoint(endpoint: OfflineWorkerEndpoint): void {\n const cancelled = new Set<number>();\n // IDs with a run() in flight, from message dispatch to its finally block.\n // A cancel naming an ID outside this set has nothing left to cancel -- the\n // run already settled, or never started -- and must not be recorded, or it\n // leaks a Set entry no later message ever clears.\n const inFlight = new Set<number>();\n\n const run = async (message: OfflineWorkerRunMessage): Promise<void> => {\n // Synchronous: runs before this async function's first `await`, so it is\n // visible to the listener below before any other message can be handled.\n inFlight.add(message.id);\n const cancelFlag = message.cancelBuffer ? new Int32Array(message.cancelBuffer) : undefined;\n const isCancelled = (): boolean =>\n cancelled.has(message.id) || (cancelFlag !== undefined && Atomics.load(cancelFlag, 0) !== 0);\n const onProgress = (progress: number, stage: string): undefined | false => {\n endpoint.postMessage({ type: 'sonare:offline-progress', id: message.id, progress, stage });\n return isCancelled() ? false : undefined;\n };\n try {\n await init();\n if (isCancelled()) {\n throw cancelledError();\n }\n\n // `cancel` is a separate channel from `onProgress`: the native call polls\n // it and never reads what the progress callback returns, so passing only\n // onProgress left a running operation no way to learn it was cancelled.\n let result: unknown;\n switch (message.operation) {\n case 'analyze':\n result = analyzeWithProgress({\n ...(message.request as unknown as MusicAnalyzeRequest),\n onProgress,\n cancel: isCancelled,\n });\n break;\n case 'detectBpm':\n result = detectBpm(message.request as unknown as SamplesRequest);\n break;\n case 'detectKey':\n result = detectKey(message.request as unknown as DetectKeyRequest);\n break;\n case 'detectChords':\n result = detectChords(message.request as unknown as DetectChordsRequest);\n break;\n case 'masterAudio':\n result = masterAudio({\n ...(message.request as unknown as MasterAudioRequest),\n onProgress,\n cancel: isCancelled,\n });\n break;\n case 'masterAudioStereo':\n result = masterAudioStereo({\n ...(message.request as unknown as MasterAudioStereoRequest),\n onProgress,\n cancel: isCancelled,\n });\n break;\n }\n if (isCancelled()) {\n throw cancelledError();\n }\n endpoint.postMessage(\n { type: 'sonare:offline-result', id: message.id, result },\n transferableBuffers(result),\n );\n } catch (error) {\n endpoint.postMessage({\n type: 'sonare:offline-error',\n id: message.id,\n error: errorMessage(error),\n });\n } finally {\n cancelled.delete(message.id);\n inFlight.delete(message.id);\n }\n };\n\n endpoint.addEventListener('message', (event) => {\n const message = event.data;\n if (message.type === 'sonare:offline-cancel') {\n if (inFlight.has(message.id)) {\n cancelled.add(message.id);\n }\n return;\n }\n void run(message);\n });\n}\n\nfunction browserWorkerEndpoint(): OfflineWorkerEndpoint | null {\n const scope = globalThis as unknown as {\n document?: unknown;\n postMessage?: (message: OfflineWorkerResponseMessage, transfer?: Transferable[]) => void;\n addEventListener?: (\n type: 'message',\n listener: (event: MessageEvent<OfflineWorkerRequestMessage>) => void,\n ) => void;\n };\n if (scope.document !== undefined || !scope.postMessage || !scope.addEventListener) {\n return null;\n }\n return {\n postMessage: (message, transfer) => scope.postMessage?.(message, transfer),\n addEventListener: (type, listener) => scope.addEventListener?.(type, listener),\n };\n}\n\nconst endpoint = browserWorkerEndpoint();\nif (endpoint) {\n installOfflineWorkerEndpoint(endpoint);\n}\n"],"mappings":"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","names":["module","requireModule","requireModule","requireModule","endpoint"]}
|