diff --git a/package-lock.json b/package-lock.json index 2f33ba6..dbd90b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,7 +5,7 @@ "requires": true, "packages": { "": { - "name": "ncs-visualizer", + "name": "audio-visualizer", "version": "1.0.0", "devDependencies": { "@sveltejs/vite-plugin-svelte": "^3.1.0", @@ -1299,4 +1299,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/App.svelte b/src/App.svelte index 704c3ee..cb75e0c 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -31,6 +31,7 @@ glowIntensity: 0.6, logoSpin: false, logoSpinSpeed: 5, + autoSubtitle: false, titlePosition: "top", }; @@ -71,7 +72,9 @@ let glowIntensity = saved.glowIntensity; let logoSpin = saved.logoSpin; let logoSpinSpeed = saved.logoSpinSpeed; + let autoSubtitle = saved.autoSubtitle; let titlePosition = saved.titlePosition; + let capturedTrackLabel = ""; let visualizerComponent; let toggleHidden = false; let hideTimer; @@ -99,6 +102,10 @@ clearTimeout(hideTimer); } + $: if (autoSubtitle && capturedTrackLabel) { + subtitle = capturedTrackLabel; + } + $: { const settings = { selectedPreset, @@ -126,6 +133,7 @@ glowIntensity, logoSpin, logoSpinSpeed, + autoSubtitle, titlePosition, }; try { @@ -183,6 +191,7 @@ glowIntensity = defaults.glowIntensity; logoSpin = defaults.logoSpin; logoSpinSpeed = defaults.logoSpinSpeed; + autoSubtitle = defaults.autoSubtitle; titlePosition = defaults.titlePosition; } @@ -311,6 +320,7 @@ {glowIntensity} {logoSpin} {logoSpinSpeed} + bind:capturedTrackLabel bind:isListening bind:fileCurrentTime bind:fileDuration @@ -381,6 +391,7 @@ bind:glowIntensity bind:logoSpin bind:logoSpinSpeed + bind:autoSubtitle bind:titlePosition {isListening} {colorPresets} diff --git a/src/lib/AudioVisualizer.svelte b/src/lib/AudioVisualizer.svelte index 1f6a294..7f39a34 100644 --- a/src/lib/AudioVisualizer.svelte +++ b/src/lib/AudioVisualizer.svelte @@ -39,6 +39,9 @@ let currentStream = null; let audioElement = null; let audioSourceNode = null; + let capturedAudioTrack = null; + let tabTitleInterval = null; + export let capturedTrackLabel = ""; let dataArray = new Uint8Array(128); let bufferLength = 128; @@ -274,6 +277,16 @@ // Stop the video track immediately — we only need audio stream.getVideoTracks().forEach((t) => t.stop()); + // Store audio track for label polling (tab title) + capturedAudioTrack = audioTracks[0]; + tabTitleInterval = setInterval(() => { + if (capturedAudioTrack && capturedAudioTrack.readyState === "live") { + capturedTrackLabel = capturedAudioTrack.label || ""; + } else { + capturedTrackLabel = ""; + } + }, 1000); + // Handle stream ending (user clicks "Stop sharing") stream.addEventListener("inactive", () => stopListening()); audioTracks.forEach((track) => @@ -721,6 +734,12 @@ audioContext = null; } audioSourceNode = null; + capturedAudioTrack = null; + if (tabTitleInterval) { + clearInterval(tabTitleInterval); + tabTitleInterval = null; + } + capturedTrackLabel = ""; isListening = false; dataArray = new Uint8Array(bufferLength); draw(); @@ -793,6 +812,7 @@ onDestroy(() => { if (animationId) cancelAnimationFrame(animationId); if (audioContext) audioContext.close(); + if (tabTitleInterval) clearInterval(tabTitleInterval); window.removeEventListener("resize", updateSize); }); @@ -807,9 +827,9 @@ {#if logoUrl}