@siteed/audio-studio 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +1073 -414
  2. package/README.md +1 -1
  3. package/android/src/main/CMakeLists.txt +3 -0
  4. package/build/cjs/AudioAnalysis/audioFeaturesWasm.js +7 -155
  5. package/build/cjs/AudioAnalysis/audioFeaturesWasm.js.map +1 -1
  6. package/build/cjs/AudioAnalysis/audioFeaturesWasm.web.js +164 -0
  7. package/build/cjs/AudioAnalysis/audioFeaturesWasm.web.js.map +1 -0
  8. package/build/cjs/AudioAnalysis/melSpectrogramWasm.js +8 -140
  9. package/build/cjs/AudioAnalysis/melSpectrogramWasm.js.map +1 -1
  10. package/build/cjs/AudioAnalysis/melSpectrogramWasm.web.js +149 -0
  11. package/build/cjs/AudioAnalysis/melSpectrogramWasm.web.js.map +1 -0
  12. package/build/cjs/prebuilt/wasm/mel-spectrogram.js +18 -0
  13. package/build/esm/AudioAnalysis/audioFeaturesWasm.js +7 -122
  14. package/build/esm/AudioAnalysis/audioFeaturesWasm.js.map +1 -1
  15. package/build/esm/AudioAnalysis/audioFeaturesWasm.web.js +126 -0
  16. package/build/esm/AudioAnalysis/audioFeaturesWasm.web.js.map +1 -0
  17. package/build/esm/AudioAnalysis/melSpectrogramWasm.js +8 -107
  18. package/build/esm/AudioAnalysis/melSpectrogramWasm.js.map +1 -1
  19. package/build/esm/AudioAnalysis/melSpectrogramWasm.web.js +111 -0
  20. package/build/esm/AudioAnalysis/melSpectrogramWasm.web.js.map +1 -0
  21. package/build/esm/prebuilt/wasm/mel-spectrogram.js +18 -0
  22. package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts +3 -15
  23. package/build/types/AudioAnalysis/audioFeaturesWasm.d.ts.map +1 -1
  24. package/build/types/AudioAnalysis/audioFeaturesWasm.web.d.ts +24 -0
  25. package/build/types/AudioAnalysis/audioFeaturesWasm.web.d.ts.map +1 -0
  26. package/build/types/AudioAnalysis/melSpectrogramWasm.d.ts +3 -15
  27. package/build/types/AudioAnalysis/melSpectrogramWasm.d.ts.map +1 -1
  28. package/build/types/AudioAnalysis/melSpectrogramWasm.web.d.ts +16 -0
  29. package/build/types/AudioAnalysis/melSpectrogramWasm.web.d.ts.map +1 -0
  30. package/package.json +3 -2
  31. package/src/AudioAnalysis/audioFeaturesWasm.ts +18 -179
  32. package/src/AudioAnalysis/audioFeaturesWasm.web.ts +200 -0
  33. package/src/AudioAnalysis/melSpectrogramWasm.ts +23 -169
  34. package/src/AudioAnalysis/melSpectrogramWasm.web.ts +179 -0
@@ -6,19 +6,7 @@ export interface AudioFeaturesWasmResult {
6
6
  mfcc: number[];
7
7
  chromagram: number[];
8
8
  }
9
- /**
10
- * Initialise the WASM streaming audio features processor.
11
- * Call once before computeAudioFeaturesFrameWasm().
12
- */
13
- export declare function initAudioFeaturesWasm(sampleRate: number, fftLength?: number, nMfcc?: number, nMelFilters?: number, computeMfcc?: boolean, computeChroma?: boolean): Promise<void>;
14
- /**
15
- * Compute audio features for a single frame via WASM C++.
16
- * Returns null if not initialised or on error.
17
- */
18
- export declare function computeAudioFeaturesFrameWasm(samples: Float32Array): AudioFeaturesWasmResult | null;
19
- /**
20
- * Compute audio features for a buffer of samples via WASM C++.
21
- * Lazy-loads the WASM module on first call.
22
- */
23
- export declare function computeAudioFeaturesWasm(audioData: Float32Array, sampleRate: number, fftLength?: number, nMfcc?: number, nMelFilters?: number, computeMfcc?: boolean, computeChroma?: boolean): Promise<AudioFeaturesWasmResult>;
9
+ export declare function initAudioFeaturesWasm(_sampleRate: number, _fftLength?: number, _nMfcc?: number, _nMelFilters?: number, _computeMfcc?: boolean, _computeChroma?: boolean): Promise<void>;
10
+ export declare function computeAudioFeaturesFrameWasm(_samples: Float32Array): AudioFeaturesWasmResult | null;
11
+ export declare function computeAudioFeaturesWasm(_audioData: Float32Array, _sampleRate: number, _fftLength?: number, _nMfcc?: number, _nMelFilters?: number, _computeMfcc?: boolean, _computeChroma?: boolean): Promise<AudioFeaturesWasmResult>;
24
12
  //# sourceMappingURL=audioFeaturesWasm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"audioFeaturesWasm.d.ts","sourceRoot":"","sources":["../../../src/AudioAnalysis/audioFeaturesWasm.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,uBAAuB;IACpC,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;CACvB;AA8ED;;;GAGG;AACH,wBAAsB,qBAAqB,CACvC,UAAU,EAAE,MAAM,EAClB,SAAS,SAAO,EAChB,KAAK,SAAK,EACV,WAAW,SAAK,EAChB,WAAW,UAAO,EAClB,aAAa,UAAO,GACrB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CACzC,OAAO,EAAE,YAAY,GACtB,uBAAuB,GAAG,IAAI,CA2BhC;AAID;;;GAGG;AACH,wBAAsB,wBAAwB,CAC1C,SAAS,EAAE,YAAY,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,SAAO,EAChB,KAAK,SAAK,EACV,WAAW,SAAK,EAChB,WAAW,UAAO,EAClB,aAAa,UAAO,GACrB,OAAO,CAAC,uBAAuB,CAAC,CA4BlC"}
1
+ {"version":3,"file":"audioFeaturesWasm.d.ts","sourceRoot":"","sources":["../../../src/AudioAnalysis/audioFeaturesWasm.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,uBAAuB;IACpC,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,wBAAsB,qBAAqB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,OAAO,EACtB,cAAc,CAAC,EAAE,OAAO,GACzB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,6BAA6B,CACzC,QAAQ,EAAE,YAAY,GACvB,uBAAuB,GAAG,IAAI,CAEhC;AAED,wBAAsB,wBAAwB,CAC1C,UAAU,EAAE,YAAY,EACxB,WAAW,EAAE,MAAM,EACnB,UAAU,CAAC,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,YAAY,CAAC,EAAE,OAAO,EACtB,cAAc,CAAC,EAAE,OAAO,GACzB,OAAO,CAAC,uBAAuB,CAAC,CAElC"}
@@ -0,0 +1,24 @@
1
+ export interface AudioFeaturesWasmResult {
2
+ spectralCentroid: number;
3
+ spectralFlatness: number;
4
+ spectralRolloff: number;
5
+ spectralBandwidth: number;
6
+ mfcc: number[];
7
+ chromagram: number[];
8
+ }
9
+ /**
10
+ * Initialise the WASM streaming audio features processor.
11
+ * Call once before computeAudioFeaturesFrameWasm().
12
+ */
13
+ export declare function initAudioFeaturesWasm(sampleRate: number, fftLength?: number, nMfcc?: number, nMelFilters?: number, computeMfcc?: boolean, computeChroma?: boolean): Promise<void>;
14
+ /**
15
+ * Compute audio features for a single frame via WASM C++.
16
+ * Returns null if not initialised or on error.
17
+ */
18
+ export declare function computeAudioFeaturesFrameWasm(samples: Float32Array): AudioFeaturesWasmResult | null;
19
+ /**
20
+ * Compute audio features for a buffer of samples via WASM C++.
21
+ * Lazy-loads the WASM module on first call.
22
+ */
23
+ export declare function computeAudioFeaturesWasm(audioData: Float32Array, sampleRate: number, fftLength?: number, nMfcc?: number, nMelFilters?: number, computeMfcc?: boolean, computeChroma?: boolean): Promise<AudioFeaturesWasmResult>;
24
+ //# sourceMappingURL=audioFeaturesWasm.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audioFeaturesWasm.web.d.ts","sourceRoot":"","sources":["../../../src/AudioAnalysis/audioFeaturesWasm.web.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,uBAAuB;IACpC,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,iBAAiB,EAAE,MAAM,CAAA;IACzB,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,UAAU,EAAE,MAAM,EAAE,CAAA;CACvB;AA8ED;;;GAGG;AACH,wBAAsB,qBAAqB,CACvC,UAAU,EAAE,MAAM,EAClB,SAAS,SAAO,EAChB,KAAK,SAAK,EACV,WAAW,SAAK,EAChB,WAAW,UAAO,EAClB,aAAa,UAAO,GACrB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CACzC,OAAO,EAAE,YAAY,GACtB,uBAAuB,GAAG,IAAI,CA2BhC;AAID;;;GAGG;AACH,wBAAsB,wBAAwB,CAC1C,SAAS,EAAE,YAAY,EACvB,UAAU,EAAE,MAAM,EAClB,SAAS,SAAO,EAChB,KAAK,SAAK,EACV,WAAW,SAAK,EAChB,WAAW,UAAO,EAClB,aAAa,UAAO,GACrB,OAAO,CAAC,uBAAuB,CAAC,CA4BlC"}
@@ -1,16 +1,4 @@
1
- /**
2
- * Initialise the WASM streaming processor. Call once before computeMelFrame().
3
- * Re-initialises only when config changes.
4
- */
5
- export declare function initMelStreamingWasm(sampleRate: number, nMels?: number, fftLength?: number, windowSizeSamples?: number, hopLengthSamples?: number, fMin?: number, fMax?: number): Promise<void>;
6
- /**
7
- * Compute a single mel spectrogram frame from raw PCM samples via WASM C++.
8
- * Returns null if not initialised or on error.
9
- */
10
- export declare function computeMelFrameWasm(samples: Float32Array): number[] | null;
11
- /**
12
- * Computes a mel spectrogram via the WASM-compiled C++ implementation.
13
- * Lazy-loads the WASM module on first call.
14
- */
15
- export declare function computeMelSpectrogramWasm(audioData: Float32Array, sampleRate: number, nMels: number, windowSizeSamples: number, hopLengthSamples: number, fMin: number, fMax: number, windowType: 'hann' | 'hamming', normalize: boolean, logScale: boolean): Promise<number[][]>;
1
+ export declare function initMelStreamingWasm(_sampleRate: number, _nMels?: number, _fftLength?: number, _windowSizeSamples?: number, _hopLengthSamples?: number, _fMin?: number, _fMax?: number): Promise<void>;
2
+ export declare function computeMelFrameWasm(_samples: Float32Array): number[] | null;
3
+ export declare function computeMelSpectrogramWasm(_audioData: Float32Array, _sampleRate: number, _nMels: number, _windowSizeSamples: number, _hopLengthSamples: number, _fMin: number, _fMax: number, _windowType: 'hann' | 'hamming', _normalize: boolean, _logScale: boolean): Promise<number[][]>;
16
4
  //# sourceMappingURL=melSpectrogramWasm.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"melSpectrogramWasm.d.ts","sourceRoot":"","sources":["../../../src/AudioAnalysis/melSpectrogramWasm.ts"],"names":[],"mappings":"AA4BA;;;GAGG;AACH,wBAAsB,oBAAoB,CACtC,UAAU,EAAE,MAAM,EAClB,KAAK,SAAM,EACX,SAAS,SAAO,EAChB,iBAAiB,SAAM,EACvB,gBAAgB,SAAM,EACtB,IAAI,SAAI,EACR,IAAI,SAAI,GACT,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI,CA4B1E;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC3C,SAAS,EAAE,YAAY,EACvB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,iBAAiB,EAAE,MAAM,EACzB,gBAAgB,EAAE,MAAM,EACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,SAAS,EAAE,OAAO,EAClB,QAAQ,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAgErB"}
1
+ {"version":3,"file":"melSpectrogramWasm.d.ts","sourceRoot":"","sources":["../../../src/AudioAnalysis/melSpectrogramWasm.ts"],"names":[],"mappings":"AAGA,wBAAsB,oBAAoB,CACtC,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,EACnB,kBAAkB,CAAC,EAAE,MAAM,EAC3B,iBAAiB,CAAC,EAAE,MAAM,EAC1B,KAAK,CAAC,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI,CAE3E;AAED,wBAAsB,yBAAyB,CAC3C,UAAU,EAAE,YAAY,EACxB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,kBAAkB,EAAE,MAAM,EAC1B,iBAAiB,EAAE,MAAM,EACzB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,OAAO,GACnB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAErB"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Initialise the WASM streaming processor. Call once before computeMelFrame().
3
+ * Re-initialises only when config changes.
4
+ */
5
+ export declare function initMelStreamingWasm(sampleRate: number, nMels?: number, fftLength?: number, windowSizeSamples?: number, hopLengthSamples?: number, fMin?: number, fMax?: number): Promise<void>;
6
+ /**
7
+ * Compute a single mel spectrogram frame from raw PCM samples via WASM C++.
8
+ * Returns null if not initialised or on error.
9
+ */
10
+ export declare function computeMelFrameWasm(samples: Float32Array): number[] | null;
11
+ /**
12
+ * Computes a mel spectrogram via the WASM-compiled C++ implementation.
13
+ * Lazy-loads the WASM module on first call.
14
+ */
15
+ export declare function computeMelSpectrogramWasm(audioData: Float32Array, sampleRate: number, nMels: number, windowSizeSamples: number, hopLengthSamples: number, fMin: number, fMax: number, windowType: 'hann' | 'hamming', normalize: boolean, logScale: boolean): Promise<number[][]>;
16
+ //# sourceMappingURL=melSpectrogramWasm.web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"melSpectrogramWasm.web.d.ts","sourceRoot":"","sources":["../../../src/AudioAnalysis/melSpectrogramWasm.web.ts"],"names":[],"mappings":"AA4BA;;;GAGG;AACH,wBAAsB,oBAAoB,CACtC,UAAU,EAAE,MAAM,EAClB,KAAK,SAAM,EACX,SAAS,SAAO,EAChB,iBAAiB,SAAM,EACvB,gBAAgB,SAAM,EACtB,IAAI,SAAI,EACR,IAAI,SAAI,GACT,OAAO,CAAC,IAAI,CAAC,CAuBf;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,EAAE,GAAG,IAAI,CA4B1E;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC3C,SAAS,EAAE,YAAY,EACvB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,iBAAiB,EAAE,MAAM,EACzB,gBAAgB,EAAE,MAAM,EACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,SAAS,EAAE,OAAO,EAClB,QAAQ,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAgErB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siteed/audio-studio",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "description": "Comprehensive audio processing library for React Native and Expo with recording, analysis, visualization, and streaming capabilities across iOS, Android, and web",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -72,7 +72,7 @@
72
72
  ],
73
73
  "scripts": {
74
74
  "build:wasm": "bash scripts/build-wasm.sh",
75
- "build": "rimraf build && yarn build:types && yarn build:cjs && yarn build:esm && yarn build:plugin",
75
+ "build": "rimraf build && yarn build:types && yarn build:cjs && yarn build:esm && yarn build:plugin && cp -r prebuilt/ build/cjs/prebuilt && cp -r prebuilt/ build/esm/prebuilt",
76
76
  "build:cjs": "tsc -p tsconfig.cjs.json",
77
77
  "build:esm": "tsc -p tsconfig.esm.json",
78
78
  "build:types": "tsc -p tsconfig.types.json",
@@ -135,6 +135,7 @@
135
135
  "typescript": "~5.8.3"
136
136
  },
137
137
  "peerDependencies": {
138
+ "@expo/config-plugins": ">=7.0.0",
138
139
  "expo": ">=52.0.0",
139
140
  "react": "*",
140
141
  "react-native": "*"
@@ -1,4 +1,4 @@
1
- import type { AudioFeaturesWasmModule } from './audio-features-wasm'
1
+ // Native stub WASM audio features is web-only.
2
2
 
3
3
  export interface AudioFeaturesWasmResult {
4
4
  spectralCentroid: number
@@ -9,192 +9,31 @@ export interface AudioFeaturesWasmResult {
9
9
  chromagram: number[]
10
10
  }
11
11
 
12
- let modulePromise: Promise<AudioFeaturesWasmModule> | null = null
13
-
14
- function getModule(): Promise<AudioFeaturesWasmModule> {
15
- if (!modulePromise) {
16
- modulePromise = (async () => {
17
- // Same WASM module as mel spectrogram (now includes audio features)
18
- // @ts-expect-error -- prebuilt Emscripten JS glue has no .d.ts
19
- const mod = await import('../../prebuilt/wasm/mel-spectrogram.js')
20
- const factory = mod.default ?? mod
21
- return factory() as Promise<AudioFeaturesWasmModule>
22
- })().catch((err) => {
23
- modulePromise = null
24
- throw err
25
- })
26
- }
27
- return modulePromise
28
- }
29
-
30
- // --- Struct layout for CAudioFeaturesResult (wasm32) ---
31
- // Offset 0: float spectralCentroid (4 bytes)
32
- // Offset 4: float spectralFlatness (4 bytes)
33
- // Offset 8: float spectralRolloff (4 bytes)
34
- // Offset 12: float spectralBandwidth (4 bytes)
35
- // Offset 16: float* mfcc (4 bytes pointer)
36
- // Offset 20: int mfccCount (4 bytes)
37
- // Offset 24: float* chromagram (4 bytes pointer)
38
- // Offset 28: int chromagramCount (4 bytes)
39
- const STRUCT_SIZE = 32
40
-
41
- function readResult(
42
- Module: AudioFeaturesWasmModule,
43
- ptr: number
44
- ): AudioFeaturesWasmResult {
45
- const spectralCentroid = Module.getValue(ptr, 'float')
46
- const spectralFlatness = Module.getValue(ptr + 4, 'float')
47
- const spectralRolloff = Module.getValue(ptr + 8, 'float')
48
- const spectralBandwidth = Module.getValue(ptr + 12, 'float')
49
-
50
- const mfccPtr = Module.getValue(ptr + 16, 'i32')
51
- const mfccCount = Module.getValue(ptr + 20, 'i32')
52
- const chromaPtr = Module.getValue(ptr + 24, 'i32')
53
- const chromaCount = Module.getValue(ptr + 28, 'i32')
54
-
55
- const mfcc: number[] = []
56
- if (mfccPtr && mfccCount > 0) {
57
- const offset = mfccPtr >> 2
58
- for (let i = 0; i < mfccCount; i++) {
59
- mfcc.push(Module.HEAPF32[offset + i])
60
- }
61
- }
62
-
63
- const chromagram: number[] = []
64
- if (chromaPtr && chromaCount > 0) {
65
- const offset = chromaPtr >> 2
66
- for (let i = 0; i < chromaCount; i++) {
67
- chromagram.push(Module.HEAPF32[offset + i])
68
- }
69
- }
70
-
71
- return {
72
- spectralCentroid,
73
- spectralFlatness,
74
- spectralRolloff,
75
- spectralBandwidth,
76
- mfcc,
77
- chromagram,
78
- }
79
- }
80
-
81
- // --- Streaming (per-frame) API ---
82
-
83
- let streamingModule: AudioFeaturesWasmModule | null = null
84
- let streamingFramePtr = 0
85
- let streamingFrameCapacity = 0
86
- let streamingResultPtr = 0
87
-
88
- /**
89
- * Initialise the WASM streaming audio features processor.
90
- * Call once before computeAudioFeaturesFrameWasm().
91
- */
92
12
  export async function initAudioFeaturesWasm(
93
- sampleRate: number,
94
- fftLength = 1024,
95
- nMfcc = 13,
96
- nMelFilters = 26,
97
- computeMfcc = true,
98
- computeChroma = true
13
+ _sampleRate: number,
14
+ _fftLength?: number,
15
+ _nMfcc?: number,
16
+ _nMelFilters?: number,
17
+ _computeMfcc?: boolean,
18
+ _computeChroma?: boolean
99
19
  ): Promise<void> {
100
- const Module = await getModule()
101
- streamingModule = Module
102
-
103
- Module._audio_features_init(
104
- sampleRate,
105
- fftLength,
106
- nMfcc,
107
- nMelFilters,
108
- computeMfcc ? 1 : 0,
109
- computeChroma ? 1 : 0
110
- )
111
-
112
- // Pre-allocate result struct on WASM heap
113
- if (streamingResultPtr) Module._free(streamingResultPtr)
114
- streamingResultPtr = Module._malloc(STRUCT_SIZE)
115
- // Zero-initialize to prevent freeing garbage pointers on first use
116
- Module.HEAPU8.fill(0, streamingResultPtr, streamingResultPtr + STRUCT_SIZE)
117
-
118
- // Frame input buffer allocated on demand
119
- streamingFrameCapacity = 0
120
- streamingFramePtr = 0
20
+ throw new Error('WASM audio features is not available on native')
121
21
  }
122
22
 
123
- /**
124
- * Compute audio features for a single frame via WASM C++.
125
- * Returns null if not initialised or on error.
126
- */
127
23
  export function computeAudioFeaturesFrameWasm(
128
- samples: Float32Array
24
+ _samples: Float32Array
129
25
  ): AudioFeaturesWasmResult | null {
130
- if (!streamingModule || !streamingResultPtr) return null
131
- const Module = streamingModule
132
-
133
- // (Re-)allocate frame input buffer if needed
134
- if (samples.length > streamingFrameCapacity) {
135
- if (streamingFramePtr) Module._free(streamingFramePtr)
136
- streamingFramePtr = Module._malloc(samples.length * 4)
137
- streamingFrameCapacity = samples.length
138
- }
139
-
140
- // Copy samples to WASM heap
141
- Module.HEAPF32.set(samples, streamingFramePtr >> 2)
142
-
143
- const ok = Module._audio_features_compute_frame(
144
- streamingFramePtr,
145
- samples.length,
146
- streamingResultPtr
147
- )
148
- if (!ok) return null
149
-
150
- const result = readResult(Module, streamingResultPtr)
151
-
152
- // Free internal arrays (mfcc, chromagram) allocated by C
153
- Module._audio_features_free_arrays(streamingResultPtr)
154
-
155
- return result
26
+ return null
156
27
  }
157
28
 
158
- // --- Batch API ---
159
-
160
- /**
161
- * Compute audio features for a buffer of samples via WASM C++.
162
- * Lazy-loads the WASM module on first call.
163
- */
164
29
  export async function computeAudioFeaturesWasm(
165
- audioData: Float32Array,
166
- sampleRate: number,
167
- fftLength = 1024,
168
- nMfcc = 13,
169
- nMelFilters = 26,
170
- computeMfcc = true,
171
- computeChroma = true
30
+ _audioData: Float32Array,
31
+ _sampleRate: number,
32
+ _fftLength?: number,
33
+ _nMfcc?: number,
34
+ _nMelFilters?: number,
35
+ _computeMfcc?: boolean,
36
+ _computeChroma?: boolean
172
37
  ): Promise<AudioFeaturesWasmResult> {
173
- const Module = await getModule()
174
-
175
- const numSamples = audioData.length
176
- const inputPtr = Module._malloc(numSamples * 4)
177
- Module.HEAPF32.set(audioData, inputPtr >> 2)
178
-
179
- const resultPtr = Module._audio_features_compute(
180
- inputPtr,
181
- numSamples,
182
- sampleRate,
183
- fftLength,
184
- nMfcc,
185
- nMelFilters,
186
- computeMfcc ? 1 : 0,
187
- computeChroma ? 1 : 0
188
- )
189
-
190
- Module._free(inputPtr)
191
-
192
- if (resultPtr === 0) {
193
- throw new Error('audio_features_compute returned null')
194
- }
195
-
196
- const result = readResult(Module, resultPtr)
197
- Module._audio_features_free(resultPtr)
198
-
199
- return result
38
+ throw new Error('WASM audio features is not available on native')
200
39
  }
@@ -0,0 +1,200 @@
1
+ import type { AudioFeaturesWasmModule } from './audio-features-wasm'
2
+
3
+ export interface AudioFeaturesWasmResult {
4
+ spectralCentroid: number
5
+ spectralFlatness: number
6
+ spectralRolloff: number
7
+ spectralBandwidth: number
8
+ mfcc: number[]
9
+ chromagram: number[]
10
+ }
11
+
12
+ let modulePromise: Promise<AudioFeaturesWasmModule> | null = null
13
+
14
+ function getModule(): Promise<AudioFeaturesWasmModule> {
15
+ if (!modulePromise) {
16
+ modulePromise = (async () => {
17
+ // Same WASM module as mel spectrogram (now includes audio features)
18
+ // @ts-expect-error -- prebuilt Emscripten JS glue has no .d.ts
19
+ const mod = await import('../../prebuilt/wasm/mel-spectrogram.js')
20
+ const factory = mod.default ?? mod
21
+ return factory() as Promise<AudioFeaturesWasmModule>
22
+ })().catch((err) => {
23
+ modulePromise = null
24
+ throw err
25
+ })
26
+ }
27
+ return modulePromise
28
+ }
29
+
30
+ // --- Struct layout for CAudioFeaturesResult (wasm32) ---
31
+ // Offset 0: float spectralCentroid (4 bytes)
32
+ // Offset 4: float spectralFlatness (4 bytes)
33
+ // Offset 8: float spectralRolloff (4 bytes)
34
+ // Offset 12: float spectralBandwidth (4 bytes)
35
+ // Offset 16: float* mfcc (4 bytes pointer)
36
+ // Offset 20: int mfccCount (4 bytes)
37
+ // Offset 24: float* chromagram (4 bytes pointer)
38
+ // Offset 28: int chromagramCount (4 bytes)
39
+ const STRUCT_SIZE = 32
40
+
41
+ function readResult(
42
+ Module: AudioFeaturesWasmModule,
43
+ ptr: number
44
+ ): AudioFeaturesWasmResult {
45
+ const spectralCentroid = Module.getValue(ptr, 'float')
46
+ const spectralFlatness = Module.getValue(ptr + 4, 'float')
47
+ const spectralRolloff = Module.getValue(ptr + 8, 'float')
48
+ const spectralBandwidth = Module.getValue(ptr + 12, 'float')
49
+
50
+ const mfccPtr = Module.getValue(ptr + 16, 'i32')
51
+ const mfccCount = Module.getValue(ptr + 20, 'i32')
52
+ const chromaPtr = Module.getValue(ptr + 24, 'i32')
53
+ const chromaCount = Module.getValue(ptr + 28, 'i32')
54
+
55
+ const mfcc: number[] = []
56
+ if (mfccPtr && mfccCount > 0) {
57
+ const offset = mfccPtr >> 2
58
+ for (let i = 0; i < mfccCount; i++) {
59
+ mfcc.push(Module.HEAPF32[offset + i])
60
+ }
61
+ }
62
+
63
+ const chromagram: number[] = []
64
+ if (chromaPtr && chromaCount > 0) {
65
+ const offset = chromaPtr >> 2
66
+ for (let i = 0; i < chromaCount; i++) {
67
+ chromagram.push(Module.HEAPF32[offset + i])
68
+ }
69
+ }
70
+
71
+ return {
72
+ spectralCentroid,
73
+ spectralFlatness,
74
+ spectralRolloff,
75
+ spectralBandwidth,
76
+ mfcc,
77
+ chromagram,
78
+ }
79
+ }
80
+
81
+ // --- Streaming (per-frame) API ---
82
+
83
+ let streamingModule: AudioFeaturesWasmModule | null = null
84
+ let streamingFramePtr = 0
85
+ let streamingFrameCapacity = 0
86
+ let streamingResultPtr = 0
87
+
88
+ /**
89
+ * Initialise the WASM streaming audio features processor.
90
+ * Call once before computeAudioFeaturesFrameWasm().
91
+ */
92
+ export async function initAudioFeaturesWasm(
93
+ sampleRate: number,
94
+ fftLength = 1024,
95
+ nMfcc = 13,
96
+ nMelFilters = 26,
97
+ computeMfcc = true,
98
+ computeChroma = true
99
+ ): Promise<void> {
100
+ const Module = await getModule()
101
+ streamingModule = Module
102
+
103
+ Module._audio_features_init(
104
+ sampleRate,
105
+ fftLength,
106
+ nMfcc,
107
+ nMelFilters,
108
+ computeMfcc ? 1 : 0,
109
+ computeChroma ? 1 : 0
110
+ )
111
+
112
+ // Pre-allocate result struct on WASM heap
113
+ if (streamingResultPtr) Module._free(streamingResultPtr)
114
+ streamingResultPtr = Module._malloc(STRUCT_SIZE)
115
+ // Zero-initialize to prevent freeing garbage pointers on first use
116
+ Module.HEAPU8.fill(0, streamingResultPtr, streamingResultPtr + STRUCT_SIZE)
117
+
118
+ // Frame input buffer allocated on demand
119
+ streamingFrameCapacity = 0
120
+ streamingFramePtr = 0
121
+ }
122
+
123
+ /**
124
+ * Compute audio features for a single frame via WASM C++.
125
+ * Returns null if not initialised or on error.
126
+ */
127
+ export function computeAudioFeaturesFrameWasm(
128
+ samples: Float32Array
129
+ ): AudioFeaturesWasmResult | null {
130
+ if (!streamingModule || !streamingResultPtr) return null
131
+ const Module = streamingModule
132
+
133
+ // (Re-)allocate frame input buffer if needed
134
+ if (samples.length > streamingFrameCapacity) {
135
+ if (streamingFramePtr) Module._free(streamingFramePtr)
136
+ streamingFramePtr = Module._malloc(samples.length * 4)
137
+ streamingFrameCapacity = samples.length
138
+ }
139
+
140
+ // Copy samples to WASM heap
141
+ Module.HEAPF32.set(samples, streamingFramePtr >> 2)
142
+
143
+ const ok = Module._audio_features_compute_frame(
144
+ streamingFramePtr,
145
+ samples.length,
146
+ streamingResultPtr
147
+ )
148
+ if (!ok) return null
149
+
150
+ const result = readResult(Module, streamingResultPtr)
151
+
152
+ // Free internal arrays (mfcc, chromagram) allocated by C
153
+ Module._audio_features_free_arrays(streamingResultPtr)
154
+
155
+ return result
156
+ }
157
+
158
+ // --- Batch API ---
159
+
160
+ /**
161
+ * Compute audio features for a buffer of samples via WASM C++.
162
+ * Lazy-loads the WASM module on first call.
163
+ */
164
+ export async function computeAudioFeaturesWasm(
165
+ audioData: Float32Array,
166
+ sampleRate: number,
167
+ fftLength = 1024,
168
+ nMfcc = 13,
169
+ nMelFilters = 26,
170
+ computeMfcc = true,
171
+ computeChroma = true
172
+ ): Promise<AudioFeaturesWasmResult> {
173
+ const Module = await getModule()
174
+
175
+ const numSamples = audioData.length
176
+ const inputPtr = Module._malloc(numSamples * 4)
177
+ Module.HEAPF32.set(audioData, inputPtr >> 2)
178
+
179
+ const resultPtr = Module._audio_features_compute(
180
+ inputPtr,
181
+ numSamples,
182
+ sampleRate,
183
+ fftLength,
184
+ nMfcc,
185
+ nMelFilters,
186
+ computeMfcc ? 1 : 0,
187
+ computeChroma ? 1 : 0
188
+ )
189
+
190
+ Module._free(inputPtr)
191
+
192
+ if (resultPtr === 0) {
193
+ throw new Error('audio_features_compute returned null')
194
+ }
195
+
196
+ const result = readResult(Module, resultPtr)
197
+ Module._audio_features_free(resultPtr)
198
+
199
+ return result
200
+ }