@viji-dev/core 0.3.26 → 0.3.27
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/README.md +1 -1
- package/dist/artist-dts-p5.js +1 -1
- package/dist/artist-dts.js +1 -1
- package/dist/artist-global.d.ts +4 -1
- package/dist/artist-jsdoc.d.ts +3 -1
- package/dist/assets/{viji.worker-PAf0oIec.js → viji.worker-jTmB7qoQ.js} +326 -85
- package/dist/assets/viji.worker-jTmB7qoQ.js.map +1 -0
- package/dist/docs-api.js +103 -49
- package/dist/{essentia-wasm.web-1yXYrWJ5.js → essentia-wasm.web-DtvIO6D8.js} +2 -2
- package/dist/{essentia-wasm.web-1yXYrWJ5.js.map → essentia-wasm.web-DtvIO6D8.js.map} +1 -1
- package/dist/{index-B8BYfP9z.js → index-9YDi9UBP.js} +1439 -1200
- package/dist/index-9YDi9UBP.js.map +1 -0
- package/dist/index.d.ts +151 -91
- package/dist/index.js +1 -1
- package/dist/shader-uniforms.js +414 -49
- package/package.json +1 -1
- package/dist/assets/viji.worker-PAf0oIec.js.map +0 -1
- package/dist/index-B8BYfP9z.js.map +0 -1
|
@@ -1792,6 +1792,7 @@ class P5WorkerAdapter {
|
|
|
1792
1792
|
this.offscreenCanvas = offscreenCanvas;
|
|
1793
1793
|
this.setupFn = sceneCode.setup || null;
|
|
1794
1794
|
this.renderFn = sceneCode.render;
|
|
1795
|
+
this.p5CanvasMode = sceneCode.canvasMode === "webgl" ? "webgl" : "2d";
|
|
1795
1796
|
this.installMinimalShims();
|
|
1796
1797
|
}
|
|
1797
1798
|
p5Instance = null;
|
|
@@ -1804,6 +1805,7 @@ class P5WorkerAdapter {
|
|
|
1804
1805
|
imageParameterCache = /* @__PURE__ */ new Map();
|
|
1805
1806
|
// Track if P5.js's main canvas has been created
|
|
1806
1807
|
mainCanvasCreated = false;
|
|
1808
|
+
p5CanvasMode;
|
|
1807
1809
|
/**
|
|
1808
1810
|
* Initialize P5 instance after P5.js library is loaded
|
|
1809
1811
|
* This must be called after the P5 class is available
|
|
@@ -1816,7 +1818,15 @@ class P5WorkerAdapter {
|
|
|
1816
1818
|
new this.p5Class((p) => {
|
|
1817
1819
|
this.p5Instance = p;
|
|
1818
1820
|
p.setup = () => {
|
|
1819
|
-
|
|
1821
|
+
if (this.p5CanvasMode === "webgl") {
|
|
1822
|
+
p.createCanvas(
|
|
1823
|
+
this.offscreenCanvas.width,
|
|
1824
|
+
this.offscreenCanvas.height,
|
|
1825
|
+
p.WEBGL
|
|
1826
|
+
);
|
|
1827
|
+
} else {
|
|
1828
|
+
p.createCanvas(this.offscreenCanvas.width, this.offscreenCanvas.height);
|
|
1829
|
+
}
|
|
1820
1830
|
p.noLoop();
|
|
1821
1831
|
this.p5InternalSetupComplete = true;
|
|
1822
1832
|
resolve();
|
|
@@ -2052,8 +2062,8 @@ class P5WorkerAdapter {
|
|
|
2052
2062
|
height: bitmap.height
|
|
2053
2063
|
};
|
|
2054
2064
|
}
|
|
2055
|
-
if (Array.isArray(vijiAPI.
|
|
2056
|
-
for (const stream of vijiAPI.
|
|
2065
|
+
if (Array.isArray(vijiAPI.videoStreams)) {
|
|
2066
|
+
for (const stream of vijiAPI.videoStreams) {
|
|
2057
2067
|
if (stream?.currentFrame instanceof OffscreenCanvas) {
|
|
2058
2068
|
const canvas = stream.currentFrame;
|
|
2059
2069
|
stream.currentFrame = {
|
|
@@ -2379,12 +2389,14 @@ class ShaderWorkerAdapter {
|
|
|
2379
2389
|
this.gl = gl;
|
|
2380
2390
|
}
|
|
2381
2391
|
}
|
|
2382
|
-
static
|
|
2392
|
+
static MAX_VIDEO_STREAMS = 8;
|
|
2383
2393
|
// Maximum number of compositor input streams
|
|
2384
2394
|
static MAX_EXTERNAL_DEVICES = 8;
|
|
2385
2395
|
// Maximum number of external devices
|
|
2386
2396
|
static MAX_DEVICE_VIDEOS = 8;
|
|
2387
2397
|
// Maximum number of device video streams
|
|
2398
|
+
static MAX_AUDIO_STREAMS = 8;
|
|
2399
|
+
// Maximum number of additional audio streams
|
|
2388
2400
|
gl;
|
|
2389
2401
|
program = null;
|
|
2390
2402
|
uniformLocations = /* @__PURE__ */ new Map();
|
|
@@ -2404,7 +2416,7 @@ class ShaderWorkerAdapter {
|
|
|
2404
2416
|
segmentationTexture = null;
|
|
2405
2417
|
keyboardTexture = null;
|
|
2406
2418
|
// Multi-stream textures
|
|
2407
|
-
|
|
2419
|
+
videoStreamTextures = [];
|
|
2408
2420
|
// Device video textures
|
|
2409
2421
|
deviceTextures = new Array(ShaderWorkerAdapter.MAX_DEVICE_VIDEOS).fill(null);
|
|
2410
2422
|
// Accumulator state (CPU-side phase accumulators for smooth parameter-driven animation)
|
|
@@ -2692,31 +2704,31 @@ uniform vec2 u_videoResolution; // Video frame width and height in pixels
|
|
|
2692
2704
|
uniform float u_videoFrameRate; // Video frame rate in frames per second
|
|
2693
2705
|
|
|
2694
2706
|
// Multi-Stream Compositor Support (using individual uniforms due to WebGL 1.0 limitations)
|
|
2695
|
-
uniform int
|
|
2696
|
-
uniform sampler2D
|
|
2697
|
-
uniform sampler2D
|
|
2698
|
-
uniform sampler2D
|
|
2699
|
-
uniform sampler2D
|
|
2700
|
-
uniform sampler2D
|
|
2701
|
-
uniform sampler2D
|
|
2702
|
-
uniform sampler2D
|
|
2703
|
-
uniform sampler2D
|
|
2704
|
-
uniform vec2
|
|
2705
|
-
uniform vec2
|
|
2706
|
-
uniform vec2
|
|
2707
|
-
uniform vec2
|
|
2708
|
-
uniform vec2
|
|
2709
|
-
uniform vec2
|
|
2710
|
-
uniform vec2
|
|
2711
|
-
uniform vec2
|
|
2712
|
-
uniform bool
|
|
2713
|
-
uniform bool
|
|
2714
|
-
uniform bool
|
|
2715
|
-
uniform bool
|
|
2716
|
-
uniform bool
|
|
2717
|
-
uniform bool
|
|
2718
|
-
uniform bool
|
|
2719
|
-
uniform bool
|
|
2707
|
+
uniform int u_videoStreamCount; // Number of available compositor input streams (0-8)
|
|
2708
|
+
uniform sampler2D u_videoStream0; // Video stream 0 texture
|
|
2709
|
+
uniform sampler2D u_videoStream1; // Video stream 1 texture
|
|
2710
|
+
uniform sampler2D u_videoStream2; // Video stream 2 texture
|
|
2711
|
+
uniform sampler2D u_videoStream3; // Video stream 3 texture
|
|
2712
|
+
uniform sampler2D u_videoStream4; // Video stream 4 texture
|
|
2713
|
+
uniform sampler2D u_videoStream5; // Video stream 5 texture
|
|
2714
|
+
uniform sampler2D u_videoStream6; // Video stream 6 texture
|
|
2715
|
+
uniform sampler2D u_videoStream7; // Video stream 7 texture
|
|
2716
|
+
uniform vec2 u_videoStream0Resolution; // Video stream 0 resolution
|
|
2717
|
+
uniform vec2 u_videoStream1Resolution; // Video stream 1 resolution
|
|
2718
|
+
uniform vec2 u_videoStream2Resolution; // Video stream 2 resolution
|
|
2719
|
+
uniform vec2 u_videoStream3Resolution; // Video stream 3 resolution
|
|
2720
|
+
uniform vec2 u_videoStream4Resolution; // Video stream 4 resolution
|
|
2721
|
+
uniform vec2 u_videoStream5Resolution; // Video stream 5 resolution
|
|
2722
|
+
uniform vec2 u_videoStream6Resolution; // Video stream 6 resolution
|
|
2723
|
+
uniform vec2 u_videoStream7Resolution; // Video stream 7 resolution
|
|
2724
|
+
uniform bool u_videoStream0Connected; // Video stream 0 connection status
|
|
2725
|
+
uniform bool u_videoStream1Connected; // Video stream 1 connection status
|
|
2726
|
+
uniform bool u_videoStream2Connected; // Video stream 2 connection status
|
|
2727
|
+
uniform bool u_videoStream3Connected; // Video stream 3 connection status
|
|
2728
|
+
uniform bool u_videoStream4Connected; // Video stream 4 connection status
|
|
2729
|
+
uniform bool u_videoStream5Connected; // Video stream 5 connection status
|
|
2730
|
+
uniform bool u_videoStream6Connected; // Video stream 6 connection status
|
|
2731
|
+
uniform bool u_videoStream7Connected; // Video stream 7 connection status
|
|
2720
2732
|
|
|
2721
2733
|
// Device Video Support (device cameras)
|
|
2722
2734
|
uniform int u_deviceCount; // Number of device videos (0-8)
|
|
@@ -2745,6 +2757,81 @@ uniform bool u_device5Connected; // Device 5 connection status
|
|
|
2745
2757
|
uniform bool u_device6Connected; // Device 6 connection status
|
|
2746
2758
|
uniform bool u_device7Connected; // Device 7 connection status
|
|
2747
2759
|
|
|
2760
|
+
// Additional Audio Streams (lightweight analysis, no beat/FFT)
|
|
2761
|
+
uniform int u_audioStreamCount; // Number of additional audio streams (0-8)
|
|
2762
|
+
uniform bool u_audioStream0Connected; // Stream 0 connection status
|
|
2763
|
+
uniform float u_audioStream0Volume; // Stream 0 volume (0-1)
|
|
2764
|
+
uniform float u_audioStream0Low; // Stream 0 low band (0-1)
|
|
2765
|
+
uniform float u_audioStream0LowMid; // Stream 0 low-mid band (0-1)
|
|
2766
|
+
uniform float u_audioStream0Mid; // Stream 0 mid band (0-1)
|
|
2767
|
+
uniform float u_audioStream0HighMid; // Stream 0 high-mid band (0-1)
|
|
2768
|
+
uniform float u_audioStream0High; // Stream 0 high band (0-1)
|
|
2769
|
+
uniform float u_audioStream0Brightness; // Stream 0 spectral brightness (0-1)
|
|
2770
|
+
uniform float u_audioStream0Flatness; // Stream 0 spectral flatness (0-1)
|
|
2771
|
+
uniform bool u_audioStream1Connected;
|
|
2772
|
+
uniform float u_audioStream1Volume;
|
|
2773
|
+
uniform float u_audioStream1Low;
|
|
2774
|
+
uniform float u_audioStream1LowMid;
|
|
2775
|
+
uniform float u_audioStream1Mid;
|
|
2776
|
+
uniform float u_audioStream1HighMid;
|
|
2777
|
+
uniform float u_audioStream1High;
|
|
2778
|
+
uniform float u_audioStream1Brightness;
|
|
2779
|
+
uniform float u_audioStream1Flatness;
|
|
2780
|
+
uniform bool u_audioStream2Connected;
|
|
2781
|
+
uniform float u_audioStream2Volume;
|
|
2782
|
+
uniform float u_audioStream2Low;
|
|
2783
|
+
uniform float u_audioStream2LowMid;
|
|
2784
|
+
uniform float u_audioStream2Mid;
|
|
2785
|
+
uniform float u_audioStream2HighMid;
|
|
2786
|
+
uniform float u_audioStream2High;
|
|
2787
|
+
uniform float u_audioStream2Brightness;
|
|
2788
|
+
uniform float u_audioStream2Flatness;
|
|
2789
|
+
uniform bool u_audioStream3Connected;
|
|
2790
|
+
uniform float u_audioStream3Volume;
|
|
2791
|
+
uniform float u_audioStream3Low;
|
|
2792
|
+
uniform float u_audioStream3LowMid;
|
|
2793
|
+
uniform float u_audioStream3Mid;
|
|
2794
|
+
uniform float u_audioStream3HighMid;
|
|
2795
|
+
uniform float u_audioStream3High;
|
|
2796
|
+
uniform float u_audioStream3Brightness;
|
|
2797
|
+
uniform float u_audioStream3Flatness;
|
|
2798
|
+
uniform bool u_audioStream4Connected;
|
|
2799
|
+
uniform float u_audioStream4Volume;
|
|
2800
|
+
uniform float u_audioStream4Low;
|
|
2801
|
+
uniform float u_audioStream4LowMid;
|
|
2802
|
+
uniform float u_audioStream4Mid;
|
|
2803
|
+
uniform float u_audioStream4HighMid;
|
|
2804
|
+
uniform float u_audioStream4High;
|
|
2805
|
+
uniform float u_audioStream4Brightness;
|
|
2806
|
+
uniform float u_audioStream4Flatness;
|
|
2807
|
+
uniform bool u_audioStream5Connected;
|
|
2808
|
+
uniform float u_audioStream5Volume;
|
|
2809
|
+
uniform float u_audioStream5Low;
|
|
2810
|
+
uniform float u_audioStream5LowMid;
|
|
2811
|
+
uniform float u_audioStream5Mid;
|
|
2812
|
+
uniform float u_audioStream5HighMid;
|
|
2813
|
+
uniform float u_audioStream5High;
|
|
2814
|
+
uniform float u_audioStream5Brightness;
|
|
2815
|
+
uniform float u_audioStream5Flatness;
|
|
2816
|
+
uniform bool u_audioStream6Connected;
|
|
2817
|
+
uniform float u_audioStream6Volume;
|
|
2818
|
+
uniform float u_audioStream6Low;
|
|
2819
|
+
uniform float u_audioStream6LowMid;
|
|
2820
|
+
uniform float u_audioStream6Mid;
|
|
2821
|
+
uniform float u_audioStream6HighMid;
|
|
2822
|
+
uniform float u_audioStream6High;
|
|
2823
|
+
uniform float u_audioStream6Brightness;
|
|
2824
|
+
uniform float u_audioStream6Flatness;
|
|
2825
|
+
uniform bool u_audioStream7Connected;
|
|
2826
|
+
uniform float u_audioStream7Volume;
|
|
2827
|
+
uniform float u_audioStream7Low;
|
|
2828
|
+
uniform float u_audioStream7LowMid;
|
|
2829
|
+
uniform float u_audioStream7Mid;
|
|
2830
|
+
uniform float u_audioStream7HighMid;
|
|
2831
|
+
uniform float u_audioStream7High;
|
|
2832
|
+
uniform float u_audioStream7Brightness;
|
|
2833
|
+
uniform float u_audioStream7Flatness;
|
|
2834
|
+
|
|
2748
2835
|
// CV - Face Detection & Expressions
|
|
2749
2836
|
uniform int u_faceCount; // Number of detected faces (0-1)
|
|
2750
2837
|
uniform vec4 u_face0Bounds; // First face bounding box (x, y, width, height) normalized 0-1
|
|
@@ -2973,7 +3060,7 @@ ${error}`);
|
|
|
2973
3060
|
if (info) {
|
|
2974
3061
|
const location = gl.getUniformLocation(this.program, info.name);
|
|
2975
3062
|
this.uniformLocations.set(info.name, location);
|
|
2976
|
-
if (info.name.includes("
|
|
3063
|
+
if (info.name.includes("Stream") || info.name.includes("stream")) {
|
|
2977
3064
|
streamUniforms.push(info.name);
|
|
2978
3065
|
}
|
|
2979
3066
|
}
|
|
@@ -2993,8 +3080,8 @@ ${error}`);
|
|
|
2993
3080
|
this.textureUnits.set("u_video", this.nextTextureUnit++);
|
|
2994
3081
|
this.textureUnits.set("u_segmentationMask", this.nextTextureUnit++);
|
|
2995
3082
|
this.textureUnits.set("u_keyboard", this.nextTextureUnit++);
|
|
2996
|
-
for (let i = 0; i < ShaderWorkerAdapter.
|
|
2997
|
-
this.textureUnits.set(`
|
|
3083
|
+
for (let i = 0; i < ShaderWorkerAdapter.MAX_VIDEO_STREAMS; i++) {
|
|
3084
|
+
this.textureUnits.set(`u_videoStream${i}`, this.nextTextureUnit++);
|
|
2998
3085
|
}
|
|
2999
3086
|
if (this.backbufferEnabled) {
|
|
3000
3087
|
this.textureUnits.set("backbuffer", this.nextTextureUnit++);
|
|
@@ -3165,18 +3252,18 @@ ${error}`);
|
|
|
3165
3252
|
this.setUniform("u_videoResolution", "vec2", [0, 0]);
|
|
3166
3253
|
this.setUniform("u_videoFrameRate", "float", 0);
|
|
3167
3254
|
}
|
|
3168
|
-
const
|
|
3169
|
-
const
|
|
3170
|
-
this.setUniform("
|
|
3171
|
-
for (let i = 0; i < ShaderWorkerAdapter.
|
|
3172
|
-
const connectedUniform = `
|
|
3173
|
-
const resolutionUniform = `
|
|
3174
|
-
if (i <
|
|
3175
|
-
this.
|
|
3255
|
+
const videoStreams = viji.videoStreams || [];
|
|
3256
|
+
const videoStreamCount = Math.min(videoStreams.length, ShaderWorkerAdapter.MAX_VIDEO_STREAMS);
|
|
3257
|
+
this.setUniform("u_videoStreamCount", "int", videoStreamCount);
|
|
3258
|
+
for (let i = 0; i < ShaderWorkerAdapter.MAX_VIDEO_STREAMS; i++) {
|
|
3259
|
+
const connectedUniform = `u_videoStream${i}Connected`;
|
|
3260
|
+
const resolutionUniform = `u_videoStream${i}Resolution`;
|
|
3261
|
+
if (i < videoStreamCount && videoStreams[i]?.isConnected && videoStreams[i]?.currentFrame) {
|
|
3262
|
+
this.updateVideoStreamTexture(i, videoStreams[i].currentFrame);
|
|
3176
3263
|
this.setUniform(
|
|
3177
3264
|
resolutionUniform,
|
|
3178
3265
|
"vec2",
|
|
3179
|
-
[
|
|
3266
|
+
[videoStreams[i].frameWidth, videoStreams[i].frameHeight]
|
|
3180
3267
|
);
|
|
3181
3268
|
this.setUniform(connectedUniform, "bool", true);
|
|
3182
3269
|
} else {
|
|
@@ -3203,6 +3290,34 @@ ${error}`);
|
|
|
3203
3290
|
this.setUniform(connectedUniform, "bool", false);
|
|
3204
3291
|
}
|
|
3205
3292
|
}
|
|
3293
|
+
const audioStreams = viji.audioStreams || [];
|
|
3294
|
+
const audioStreamCount = Math.min(audioStreams.length, ShaderWorkerAdapter.MAX_AUDIO_STREAMS);
|
|
3295
|
+
this.setUniform("u_audioStreamCount", "int", audioStreamCount);
|
|
3296
|
+
for (let i = 0; i < ShaderWorkerAdapter.MAX_AUDIO_STREAMS; i++) {
|
|
3297
|
+
const prefix = `u_audioStream${i}`;
|
|
3298
|
+
if (i < audioStreamCount && audioStreams[i]?.isConnected) {
|
|
3299
|
+
const s = audioStreams[i];
|
|
3300
|
+
this.setUniform(`${prefix}Connected`, "bool", true);
|
|
3301
|
+
this.setUniform(`${prefix}Volume`, "float", s.volume?.current || 0);
|
|
3302
|
+
this.setUniform(`${prefix}Low`, "float", s.bands?.low || 0);
|
|
3303
|
+
this.setUniform(`${prefix}LowMid`, "float", s.bands?.lowMid || 0);
|
|
3304
|
+
this.setUniform(`${prefix}Mid`, "float", s.bands?.mid || 0);
|
|
3305
|
+
this.setUniform(`${prefix}HighMid`, "float", s.bands?.highMid || 0);
|
|
3306
|
+
this.setUniform(`${prefix}High`, "float", s.bands?.high || 0);
|
|
3307
|
+
this.setUniform(`${prefix}Brightness`, "float", s.spectral?.brightness || 0);
|
|
3308
|
+
this.setUniform(`${prefix}Flatness`, "float", s.spectral?.flatness || 0);
|
|
3309
|
+
} else {
|
|
3310
|
+
this.setUniform(`${prefix}Connected`, "bool", false);
|
|
3311
|
+
this.setUniform(`${prefix}Volume`, "float", 0);
|
|
3312
|
+
this.setUniform(`${prefix}Low`, "float", 0);
|
|
3313
|
+
this.setUniform(`${prefix}LowMid`, "float", 0);
|
|
3314
|
+
this.setUniform(`${prefix}Mid`, "float", 0);
|
|
3315
|
+
this.setUniform(`${prefix}HighMid`, "float", 0);
|
|
3316
|
+
this.setUniform(`${prefix}High`, "float", 0);
|
|
3317
|
+
this.setUniform(`${prefix}Brightness`, "float", 0);
|
|
3318
|
+
this.setUniform(`${prefix}Flatness`, "float", 0);
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3206
3321
|
const faces = video.faces || [];
|
|
3207
3322
|
this.setUniform("u_faceCount", "int", faces.length);
|
|
3208
3323
|
if (faces.length > 0) {
|
|
@@ -3732,18 +3847,18 @@ ${error}`);
|
|
|
3732
3847
|
}
|
|
3733
3848
|
}
|
|
3734
3849
|
/**
|
|
3735
|
-
* Update compositor stream texture at specified index
|
|
3850
|
+
* Update compositor video stream texture at specified index
|
|
3736
3851
|
* Supports both OffscreenCanvas and ImageBitmap for zero-copy pipeline
|
|
3737
3852
|
*/
|
|
3738
|
-
|
|
3853
|
+
updateVideoStreamTexture(index, streamFrame) {
|
|
3739
3854
|
const gl = this.gl;
|
|
3740
|
-
const uniformName = `
|
|
3855
|
+
const uniformName = `u_videoStream${index}`;
|
|
3741
3856
|
const unit = this.textureUnits.get(uniformName);
|
|
3742
|
-
if (!this.
|
|
3743
|
-
this.
|
|
3857
|
+
if (!this.videoStreamTextures[index]) {
|
|
3858
|
+
this.videoStreamTextures[index] = gl.createTexture();
|
|
3744
3859
|
}
|
|
3745
3860
|
gl.activeTexture(gl.TEXTURE0 + unit);
|
|
3746
|
-
gl.bindTexture(gl.TEXTURE_2D, this.
|
|
3861
|
+
gl.bindTexture(gl.TEXTURE_2D, this.videoStreamTextures[index]);
|
|
3747
3862
|
const shouldFlip = streamFrame instanceof OffscreenCanvas;
|
|
3748
3863
|
if (shouldFlip) {
|
|
3749
3864
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
|
|
@@ -3934,10 +4049,10 @@ ${error}`);
|
|
|
3934
4049
|
if (this.audioWaveformTexture) gl.deleteTexture(this.audioWaveformTexture);
|
|
3935
4050
|
if (this.videoTexture) gl.deleteTexture(this.videoTexture);
|
|
3936
4051
|
if (this.segmentationTexture) gl.deleteTexture(this.segmentationTexture);
|
|
3937
|
-
for (const texture of this.
|
|
4052
|
+
for (const texture of this.videoStreamTextures) {
|
|
3938
4053
|
if (texture) gl.deleteTexture(texture);
|
|
3939
4054
|
}
|
|
3940
|
-
this.
|
|
4055
|
+
this.videoStreamTextures = [];
|
|
3941
4056
|
for (const texture of this.deviceTextures) {
|
|
3942
4057
|
if (texture) gl.deleteTexture(texture);
|
|
3943
4058
|
}
|
|
@@ -4027,6 +4142,11 @@ class VijiWorkerRuntime {
|
|
|
4027
4142
|
};
|
|
4028
4143
|
// Map deviceId → streamIndex for O(1) device video lookup
|
|
4029
4144
|
deviceVideoMap = /* @__PURE__ */ new Map();
|
|
4145
|
+
// Audio stream state management (mirroring video stream pattern)
|
|
4146
|
+
static AUDIO_ADDITIONAL_BASE = 1;
|
|
4147
|
+
static AUDIO_DEVICE_BASE = 100;
|
|
4148
|
+
audioStreamStates = /* @__PURE__ */ new Map();
|
|
4149
|
+
deviceAudioMap = /* @__PURE__ */ new Map();
|
|
4030
4150
|
// Video state is now managed by the worker-side VideoSystem
|
|
4031
4151
|
// Artist API object
|
|
4032
4152
|
viji = {
|
|
@@ -4124,7 +4244,9 @@ class VijiWorkerRuntime {
|
|
|
4124
4244
|
}
|
|
4125
4245
|
},
|
|
4126
4246
|
// Additional video streams (index 1+, no CV)
|
|
4127
|
-
|
|
4247
|
+
videoStreams: [],
|
|
4248
|
+
// Additional audio streams (lightweight analysis, no beat detection)
|
|
4249
|
+
audioStreams: [],
|
|
4128
4250
|
// Interaction APIs will be added during construction
|
|
4129
4251
|
mouse: {},
|
|
4130
4252
|
keyboard: {},
|
|
@@ -4195,7 +4317,7 @@ class VijiWorkerRuntime {
|
|
|
4195
4317
|
* Initialize P5.js mode
|
|
4196
4318
|
* Sets up P5 rendering with P5WorkerAdapter
|
|
4197
4319
|
*/
|
|
4198
|
-
async initP5Mode(setup, render) {
|
|
4320
|
+
async initP5Mode(setup, render, options) {
|
|
4199
4321
|
try {
|
|
4200
4322
|
this.rendererType = "p5";
|
|
4201
4323
|
this.debugLog("🎨 Initializing P5.js mode...");
|
|
@@ -4204,7 +4326,8 @@ class VijiWorkerRuntime {
|
|
|
4204
4326
|
this.viji,
|
|
4205
4327
|
{
|
|
4206
4328
|
setup,
|
|
4207
|
-
render
|
|
4329
|
+
render,
|
|
4330
|
+
canvasMode: options?.canvasMode === "webgl" ? "webgl" : "2d"
|
|
4208
4331
|
}
|
|
4209
4332
|
);
|
|
4210
4333
|
await this.p5Adapter.init();
|
|
@@ -4296,20 +4419,47 @@ class VijiWorkerRuntime {
|
|
|
4296
4419
|
if (this.videoSystems[0]) {
|
|
4297
4420
|
Object.assign(this.viji.video, this.videoSystems[0].getVideoAPI());
|
|
4298
4421
|
}
|
|
4299
|
-
this.
|
|
4422
|
+
this.updateVijiVideoStreams();
|
|
4300
4423
|
}
|
|
4301
4424
|
/**
|
|
4302
|
-
* Updates viji.
|
|
4425
|
+
* Updates viji.videoStreams from videoSystems array.
|
|
4303
4426
|
* Collects 'additional' MediaStreams first, then 'directFrame' injected frames.
|
|
4304
4427
|
* Excludes 'main' and 'device' streams (those go to viji.video and viji.devices[].video).
|
|
4305
4428
|
*/
|
|
4306
|
-
|
|
4429
|
+
updateVijiVideoStreams() {
|
|
4307
4430
|
const additional = this.videoSystems.filter((vs) => vs && vs.getStreamType() === "additional").map((vs) => vs.getVideoAPI());
|
|
4308
4431
|
const directFrames = this.videoSystems.filter((vs) => vs && vs.getStreamType() === "directFrame").map((vs) => vs.getVideoAPI());
|
|
4309
4432
|
const freshStreams = [...additional, ...directFrames];
|
|
4310
|
-
this.viji.
|
|
4433
|
+
this.viji.videoStreams.length = freshStreams.length;
|
|
4311
4434
|
for (let i = 0; i < freshStreams.length; i++) {
|
|
4312
|
-
this.viji.
|
|
4435
|
+
this.viji.videoStreams[i] = freshStreams[i];
|
|
4436
|
+
}
|
|
4437
|
+
}
|
|
4438
|
+
/**
|
|
4439
|
+
* Rebuilds viji.audioStreams from audioStreamStates.
|
|
4440
|
+
* Collects entries in the additional range (1-99), maps to AudioStreamAPI objects.
|
|
4441
|
+
*/
|
|
4442
|
+
updateVijiAudioStreams() {
|
|
4443
|
+
const entries = [];
|
|
4444
|
+
for (const [idx, state2] of this.audioStreamStates) {
|
|
4445
|
+
if (idx >= VijiWorkerRuntime.AUDIO_ADDITIONAL_BASE && idx < VijiWorkerRuntime.AUDIO_DEVICE_BASE) {
|
|
4446
|
+
entries.push({ index: idx, ...state2 });
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4449
|
+
entries.sort((a, b) => a.index - b.index);
|
|
4450
|
+
this.viji.audioStreams.length = entries.length;
|
|
4451
|
+
for (let i = 0; i < entries.length; i++) {
|
|
4452
|
+
const s = entries[i];
|
|
4453
|
+
const freqData = s.frequencyData;
|
|
4454
|
+
const waveData = s.waveformData;
|
|
4455
|
+
this.viji.audioStreams[i] = {
|
|
4456
|
+
isConnected: s.isConnected,
|
|
4457
|
+
volume: s.volume,
|
|
4458
|
+
bands: s.bands,
|
|
4459
|
+
spectral: s.spectral,
|
|
4460
|
+
getFrequencyData: () => freqData,
|
|
4461
|
+
getWaveform: () => waveData
|
|
4462
|
+
};
|
|
4313
4463
|
}
|
|
4314
4464
|
}
|
|
4315
4465
|
// Send all parameters (from helper functions) to host
|
|
@@ -4353,6 +4503,9 @@ class VijiWorkerRuntime {
|
|
|
4353
4503
|
case "audio-analysis-update":
|
|
4354
4504
|
this.handleAudioAnalysisUpdate(message);
|
|
4355
4505
|
break;
|
|
4506
|
+
case "audio-stream-setup":
|
|
4507
|
+
this.handleAudioStreamSetup(message);
|
|
4508
|
+
break;
|
|
4356
4509
|
case "video-canvas-setup":
|
|
4357
4510
|
this.handleVideoCanvasSetup(message);
|
|
4358
4511
|
break;
|
|
@@ -4522,6 +4675,14 @@ class VijiWorkerRuntime {
|
|
|
4522
4675
|
}
|
|
4523
4676
|
handleAudioAnalysisUpdate(message) {
|
|
4524
4677
|
const d = message.data;
|
|
4678
|
+
const streamIndex = d.streamIndex ?? 0;
|
|
4679
|
+
if (streamIndex === 0) {
|
|
4680
|
+
this.handleMainAudioUpdate(d);
|
|
4681
|
+
} else {
|
|
4682
|
+
this.handleAdditionalAudioUpdate(streamIndex, d);
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
handleMainAudioUpdate(d) {
|
|
4525
4686
|
const audio = this.viji.audio;
|
|
4526
4687
|
audio.isConnected = d.isConnected;
|
|
4527
4688
|
audio.volume.current = d.volume.current;
|
|
@@ -4537,30 +4698,78 @@ class VijiWorkerRuntime {
|
|
|
4537
4698
|
audio.bands.midSmoothed = d.bands.midSmoothed;
|
|
4538
4699
|
audio.bands.highMidSmoothed = d.bands.highMidSmoothed;
|
|
4539
4700
|
audio.bands.highSmoothed = d.bands.highSmoothed;
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
4558
|
-
|
|
4701
|
+
if (d.beat) {
|
|
4702
|
+
audio.beat.kick = d.beat.kick;
|
|
4703
|
+
audio.beat.snare = d.beat.snare;
|
|
4704
|
+
audio.beat.hat = d.beat.hat;
|
|
4705
|
+
audio.beat.any = d.beat.any;
|
|
4706
|
+
audio.beat.kickSmoothed = d.beat.kickSmoothed;
|
|
4707
|
+
audio.beat.snareSmoothed = d.beat.snareSmoothed;
|
|
4708
|
+
audio.beat.hatSmoothed = d.beat.hatSmoothed;
|
|
4709
|
+
audio.beat.anySmoothed = d.beat.anySmoothed;
|
|
4710
|
+
const events = d.beat.events || [];
|
|
4711
|
+
if (events.length > 0) {
|
|
4712
|
+
audio.beat.triggers.kick = audio.beat.triggers.kick || events.some((e) => e.type === "kick");
|
|
4713
|
+
audio.beat.triggers.snare = audio.beat.triggers.snare || events.some((e) => e.type === "snare");
|
|
4714
|
+
audio.beat.triggers.hat = audio.beat.triggers.hat || events.some((e) => e.type === "hat");
|
|
4715
|
+
audio.beat.triggers.any = true;
|
|
4716
|
+
audio.beat.events.push(...events);
|
|
4717
|
+
}
|
|
4718
|
+
audio.beat.bpm = d.beat.bpm;
|
|
4719
|
+
audio.beat.confidence = d.beat.confidence;
|
|
4720
|
+
audio.beat.isLocked = d.beat.isLocked;
|
|
4721
|
+
}
|
|
4559
4722
|
audio.spectral.brightness = d.spectral.brightness;
|
|
4560
4723
|
audio.spectral.flatness = d.spectral.flatness;
|
|
4561
4724
|
this.audioFrequencyData = new Uint8Array(d.frequencyData);
|
|
4562
4725
|
this.audioWaveformData = d.waveformData ? new Float32Array(d.waveformData) : new Float32Array(0);
|
|
4563
4726
|
}
|
|
4727
|
+
handleAdditionalAudioUpdate(streamIndex, d) {
|
|
4728
|
+
const frequencyData = new Uint8Array(d.frequencyData);
|
|
4729
|
+
const waveformData = d.waveformData ? new Float32Array(d.waveformData) : new Float32Array(0);
|
|
4730
|
+
this.audioStreamStates.set(streamIndex, {
|
|
4731
|
+
isConnected: d.isConnected,
|
|
4732
|
+
volume: { ...d.volume },
|
|
4733
|
+
bands: { ...d.bands },
|
|
4734
|
+
spectral: { ...d.spectral },
|
|
4735
|
+
frequencyData,
|
|
4736
|
+
waveformData
|
|
4737
|
+
});
|
|
4738
|
+
this.updateVijiAudioStreams();
|
|
4739
|
+
}
|
|
4740
|
+
/**
|
|
4741
|
+
* Handles audio-stream-setup: registers stream type and device mapping.
|
|
4742
|
+
* Mirrors handleVideoCanvasSetup — two-phase protocol where setup establishes
|
|
4743
|
+
* the stream identity, and subsequent audio-analysis-update messages carry data.
|
|
4744
|
+
*/
|
|
4745
|
+
handleAudioStreamSetup(message) {
|
|
4746
|
+
const { streamIndex, streamType, deviceId } = message.data;
|
|
4747
|
+
switch (streamType) {
|
|
4748
|
+
case "additional":
|
|
4749
|
+
this.updateVijiAudioStreams();
|
|
4750
|
+
break;
|
|
4751
|
+
case "device":
|
|
4752
|
+
if (deviceId) {
|
|
4753
|
+
this.deviceAudioMap.set(deviceId, streamIndex);
|
|
4754
|
+
const device = this.viji.devices.find((d) => d.id === deviceId);
|
|
4755
|
+
if (device) {
|
|
4756
|
+
const audioState = this.audioStreamStates.get(streamIndex);
|
|
4757
|
+
if (audioState) {
|
|
4758
|
+
device.audio = {
|
|
4759
|
+
isConnected: audioState.isConnected,
|
|
4760
|
+
volume: audioState.volume,
|
|
4761
|
+
bands: audioState.bands,
|
|
4762
|
+
spectral: audioState.spectral,
|
|
4763
|
+
getFrequencyData: () => audioState.frequencyData,
|
|
4764
|
+
getWaveform: () => audioState.waveformData
|
|
4765
|
+
};
|
|
4766
|
+
}
|
|
4767
|
+
}
|
|
4768
|
+
}
|
|
4769
|
+
break;
|
|
4770
|
+
}
|
|
4771
|
+
this.debugLog(`Audio stream setup at index ${streamIndex}, type: ${streamType}${deviceId ? `, deviceId: ${deviceId}` : ""}`);
|
|
4772
|
+
}
|
|
4564
4773
|
/**
|
|
4565
4774
|
* Reset frame-scoped audio events (triggers + events array).
|
|
4566
4775
|
* Called after each render, mirroring interactionSystem.frameStart().
|
|
@@ -4613,6 +4822,9 @@ class VijiWorkerRuntime {
|
|
|
4613
4822
|
audio.spectral.flatness = 0;
|
|
4614
4823
|
this.audioFrequencyData = new Uint8Array(0);
|
|
4615
4824
|
this.audioWaveformData = new Float32Array(0);
|
|
4825
|
+
this.audioStreamStates.clear();
|
|
4826
|
+
this.deviceAudioMap.clear();
|
|
4827
|
+
this.viji.audioStreams.length = 0;
|
|
4616
4828
|
}
|
|
4617
4829
|
handleVideoCanvasSetup(message) {
|
|
4618
4830
|
const { streamIndex, streamType, deviceId } = message.data;
|
|
@@ -4633,7 +4845,7 @@ class VijiWorkerRuntime {
|
|
|
4633
4845
|
Object.assign(this.viji.video, videoSystem.getVideoAPI());
|
|
4634
4846
|
break;
|
|
4635
4847
|
case "additional":
|
|
4636
|
-
this.
|
|
4848
|
+
this.updateVijiVideoStreams();
|
|
4637
4849
|
break;
|
|
4638
4850
|
case "device":
|
|
4639
4851
|
if (deviceId) {
|
|
@@ -4724,7 +4936,7 @@ class VijiWorkerRuntime {
|
|
|
4724
4936
|
this.videoSystems[index].setDebugMode(this.debugMode);
|
|
4725
4937
|
this.videoSystems[index].initializeForDirectFrames(this.rendererType);
|
|
4726
4938
|
}
|
|
4727
|
-
this.
|
|
4939
|
+
this.updateVijiVideoStreams();
|
|
4728
4940
|
this.debugLog(`[Compositor] Prepared ${directFrameCount} direct frame slot(s)`);
|
|
4729
4941
|
}
|
|
4730
4942
|
handleVideoFrameDirect(message) {
|
|
@@ -4852,7 +5064,8 @@ class VijiWorkerRuntime {
|
|
|
4852
5064
|
renderFrame() {
|
|
4853
5065
|
if (!this.isRunning) return;
|
|
4854
5066
|
const currentTime = performance.now();
|
|
4855
|
-
this.
|
|
5067
|
+
this.updateVijiVideoStreams();
|
|
5068
|
+
this.updateVijiAudioStreams();
|
|
4856
5069
|
this.viji.fps = this.frameRateMode === "full" ? this.screenRefreshRate : this.screenRefreshRate / 2;
|
|
4857
5070
|
let shouldRender = true;
|
|
4858
5071
|
if (this.frameRateMode === "half") {
|
|
@@ -4952,17 +5165,29 @@ class VijiWorkerRuntime {
|
|
|
4952
5165
|
this.viji.device = this.deviceState.device;
|
|
4953
5166
|
const updatedDevices = this.deviceState.devices.map((deviceData) => {
|
|
4954
5167
|
const existingDevice = this.viji.devices.find((d) => d.id === deviceData.id);
|
|
5168
|
+
const videoStreamIndex = this.deviceVideoMap.get(deviceData.id);
|
|
5169
|
+
const videoSystem = videoStreamIndex !== void 0 ? this.videoSystems[videoStreamIndex] : void 0;
|
|
5170
|
+
const audioStreamIndex = this.deviceAudioMap.get(deviceData.id);
|
|
5171
|
+
const audioState = audioStreamIndex !== void 0 ? this.audioStreamStates.get(audioStreamIndex) : void 0;
|
|
5172
|
+
const audioAPI = audioState ? {
|
|
5173
|
+
isConnected: audioState.isConnected,
|
|
5174
|
+
volume: audioState.volume,
|
|
5175
|
+
bands: audioState.bands,
|
|
5176
|
+
spectral: audioState.spectral,
|
|
5177
|
+
getFrequencyData: () => audioState.frequencyData,
|
|
5178
|
+
getWaveform: () => audioState.waveformData
|
|
5179
|
+
} : null;
|
|
4955
5180
|
if (existingDevice) {
|
|
4956
5181
|
existingDevice.name = deviceData.name;
|
|
4957
5182
|
existingDevice.motion = deviceData.motion;
|
|
4958
5183
|
existingDevice.orientation = deviceData.orientation;
|
|
5184
|
+
if (audioAPI) existingDevice.audio = audioAPI;
|
|
4959
5185
|
return existingDevice;
|
|
4960
5186
|
} else {
|
|
4961
|
-
const streamIndex = this.deviceVideoMap.get(deviceData.id);
|
|
4962
|
-
const videoSystem = streamIndex !== void 0 ? this.videoSystems[streamIndex] : void 0;
|
|
4963
5187
|
return {
|
|
4964
5188
|
...deviceData,
|
|
4965
|
-
video: videoSystem ? videoSystem.getVideoAPI() : null
|
|
5189
|
+
video: videoSystem ? videoSystem.getVideoAPI() : null,
|
|
5190
|
+
audio: audioAPI
|
|
4966
5191
|
};
|
|
4967
5192
|
}
|
|
4968
5193
|
});
|
|
@@ -4991,6 +5216,21 @@ class SceneAnalyzer {
|
|
|
4991
5216
|
}
|
|
4992
5217
|
return "native";
|
|
4993
5218
|
}
|
|
5219
|
+
/**
|
|
5220
|
+
* P5 main-canvas mode from the renderer directive (only meaningful when
|
|
5221
|
+
* {@link detectRendererType} is `'p5'`).
|
|
5222
|
+
*
|
|
5223
|
+
* - `// @renderer p5` → 2D (default)
|
|
5224
|
+
* - `// @renderer p5 webgl` → WEBGL
|
|
5225
|
+
*/
|
|
5226
|
+
static detectP5CanvasMode(sceneCode) {
|
|
5227
|
+
if (/\/\/\s*@renderer\s+p5\s+webgl\b|\/\*\s*@renderer\s+p5\s+webgl\s*\*\//i.test(
|
|
5228
|
+
sceneCode
|
|
5229
|
+
)) {
|
|
5230
|
+
return "webgl";
|
|
5231
|
+
}
|
|
5232
|
+
return "2d";
|
|
5233
|
+
}
|
|
4994
5234
|
}
|
|
4995
5235
|
var ContextualKeyword;
|
|
4996
5236
|
(function(ContextualKeyword2) {
|
|
@@ -26312,6 +26552,7 @@ async function setSceneCode(sceneCode) {
|
|
|
26312
26552
|
await runtime.initShaderMode(sceneCode);
|
|
26313
26553
|
runtime.sendAllParametersToHost();
|
|
26314
26554
|
} else if (rendererType === "p5") {
|
|
26555
|
+
const p5CanvasMode = SceneAnalyzer.detectP5CanvasMode(sceneCode);
|
|
26315
26556
|
const jsCode = prepareSceneCode(sceneCode);
|
|
26316
26557
|
const functionBody = jsCode + '\nreturn { setup: typeof setup !== "undefined" ? setup : null, render: typeof render !== "undefined" ? render : null };';
|
|
26317
26558
|
const sceneFunction = new Function("viji", "p5", functionBody);
|
|
@@ -26319,7 +26560,7 @@ async function setSceneCode(sceneCode) {
|
|
|
26319
26560
|
if (!render) {
|
|
26320
26561
|
throw new Error("P5 mode requires a render(viji, p5) function");
|
|
26321
26562
|
}
|
|
26322
|
-
await runtime.initP5Mode(setup, render);
|
|
26563
|
+
await runtime.initP5Mode(setup, render, { canvasMode: p5CanvasMode });
|
|
26323
26564
|
runtime.sendAllParametersToHost();
|
|
26324
26565
|
} else {
|
|
26325
26566
|
const jsCode = prepareSceneCode(sceneCode);
|
|
@@ -26345,4 +26586,4 @@ async function setSceneCode(sceneCode) {
|
|
|
26345
26586
|
}
|
|
26346
26587
|
}
|
|
26347
26588
|
self.setSceneCode = setSceneCode;
|
|
26348
|
-
//# sourceMappingURL=viji.worker-
|
|
26589
|
+
//# sourceMappingURL=viji.worker-jTmB7qoQ.js.map
|