[READ-ONLY] Mirror of https://github.com/flo-bit/svelte-audio-visualizations. a few different simple audio visualizations (esp for voice input/output) for svelte flo-bit.dev/svelte-audio-visualizations/
0

Configure Feed

Select the types of activity you want to include in your feed.

update

Florian (Oct 14, 2024, 2:54 PM +0200) 698d7fd5 71af397e

+282 -193
+41 -3
README.md
··· 10 10 11 11 ## Usage 12 12 13 - All visualizations expect some props to be passed to them. 13 + There are two ways you can use the visualizations: 14 + 15 + 1. Using with a `WavRecorder`, `WavStreamPlayer` or `AudioFilePlayer` instance. For this use the components in the `lib/visualizations/audio` folder ending with `AudioVisualizer`. 16 + 17 + ```svelte 18 + <script lang="ts"> 19 + import { AudioFilePlayer } from '$lib/visualizations/wavtools'; 14 20 15 - The one required prop is `audioInput`, which can be either of type `WavRecorder`, `WavStreamPlayer` or `AudioFilePlayer` or a function that returns a normalized (between 0-1) Float32Array of the current frequency data. for other props, see the individual visualizations. 21 + let audio: AudioFilePlayer | null = null; 16 22 17 - see the `src/routes/+page.svelte` file for an example of how to use the visualizations. 23 + function playMusic() { 24 + audio = new AudioFilePlayer(); 25 + audio.loadFile('/svelte-audio-visualizations/music.mp3').then(() => audio.play()); 26 + } 27 + </script> 28 + 29 + <button on:click={playMusic}>Play music</button> 30 + 31 + {#if audio} 32 + <CircleBarAudioVisualizer {audio} /> 33 + {/if} 34 + ``` 35 + 36 + 2. Passing in values yourself. For this use the components in the `lib/visualizations/core` folder. Ending just in `Visualizer`. 37 + 38 + ```svelte 39 + <script lang="ts"> 40 + import DeformedCircleVisualizer from '$lib/visualizations/core/DeformedCircleVisualizer.svelte'; 41 + </script> 42 + 43 + <CircleBarVisualizer values={new Float32Array([0, 1, 0, 1, 0, 1])} /> 44 + ``` 45 + 46 + For this a normalized Float32Array is expected, where each value is between 0 and 1. Also note, that the length of the array influences the visualizations (e.g. number of bars in the `BarVisualizer`). To convert from any length array, to a specific length, you can use the `normalizeArray` function. 47 + 48 + ```ts 49 + import { normalizeArray } from '$lib/visualizations/core/utils'; 50 + 51 + const values = new Float32Array([0, 1, 0, 1, 0, 1]); 52 + 53 + const normalizedValues = normalizeArray(values, 10); 54 + ``` 55 + 18 56 19 57 ## Credits 20 58
-18
src/lib/visualizations/AudioFrequency.svelte
··· 1 - <script lang="ts"> 2 - import type { WavRecorder, AudioFilePlayer } from '$lib/visualizations/wavtools'; 3 - import { raf } from "./raf"; 4 - import { normalizeArray } from "./wav_helper"; 5 - 6 - export let audio:AudioFilePlayer | WavRecorder | null; 7 - 8 - let values:Float32Array = new Float32Array([0]); 9 - 10 - //Update frequency values every render frame 11 - raf(() => values = audio ? audio.getFrequencies('music').values : new Float32Array([0])); 12 - 13 - //Recreate the getValues function when values changes (to trigger reactivity) 14 - $:getValues = (detail:number)=>normalizeArray(values, detail) 15 - 16 - </script> 17 - 18 - <slot {values} {getValues} />
+6 -8
src/lib/visualizations/BarVisualizer.svelte src/lib/visualizations/core/BarVisualizer.svelte
··· 1 1 <script lang="ts"> 2 - export let values:Float32Array; 2 + export let values: Float32Array; 3 3 4 4 export let color: string | undefined = undefined; 5 5 export let startHue: number | undefined = undefined; ··· 9 9 export let center = false; 10 10 11 11 let canvas: HTMLCanvasElement; 12 - let contentRect:DOMRectReadOnly; 12 + let contentRect: DOMRectReadOnly; 13 13 14 - $:if(canvas && contentRect){ 14 + $: if (canvas && contentRect) { 15 15 const ctx = canvas.getContext('2d')!; 16 16 17 17 //Update canvas size 18 - canvas.width = Math.round(contentRect.width); 19 - canvas.height = Math.round(contentRect.height); 18 + canvas.width = Math.round(contentRect.width) * 2; 19 + canvas.height = Math.round(contentRect.height) * 2; 20 20 21 21 //Clear 22 22 ctx.clearRect(0, 0, canvas.width, canvas.height); ··· 47 47 } 48 48 ctx.fillRect(x, y, width, height); 49 49 } 50 - }; 51 - 50 + } 52 51 </script> 53 52 54 53 <canvas bind:this={canvas} bind:contentRect class="w-full h-full"></canvas> 55 -
-19
src/lib/visualizations/CircleBarAudioVisualizer.svelte
··· 1 - <script lang="ts"> 2 - import type { WavRecorder, AudioFilePlayer } from '$lib/visualizations/wavtools'; 3 - import AudioFrequency from './AudioFrequency.svelte'; 4 - import Glow from './Glow.svelte'; 5 - import CircleBarVisualizer from './CircleBarVisualizer.svelte'; 6 - 7 - export let audio:AudioFilePlayer | WavRecorder | null; 8 - export let glow:number | undefined = 3; 9 - export let detail:number | undefined = 50; 10 - </script> 11 - 12 - <AudioFrequency {audio} let:getValues > 13 - <Glow {glow}> 14 - <CircleBarVisualizer 15 - values={getValues(detail || 50)} 16 - {...$$restProps} 17 - /> 18 - </Glow> 19 - </AudioFrequency>
+5 -6
src/lib/visualizations/CircleBarVisualizer.svelte src/lib/visualizations/core/CircleBarVisualizer.svelte
··· 1 1 <script lang="ts"> 2 - export let values:Float32Array; 2 + export let values: Float32Array; 3 3 4 4 export let color: string | undefined = undefined; 5 5 export let startHue: number | undefined = undefined; ··· 10 10 export let varyBrightness = false; 11 11 12 12 let canvas: HTMLCanvasElement; 13 - let contentRect:DOMRectReadOnly; 13 + let contentRect: DOMRectReadOnly; 14 14 15 - $:if(canvas && contentRect){ 15 + $: if (canvas && contentRect) { 16 16 const ctx = canvas.getContext('2d')!; 17 17 18 18 //Update canvas size 19 - canvas.width = Math.round(contentRect.width); 20 - canvas.height = Math.round(contentRect.height); 19 + canvas.width = Math.round(contentRect.width) * 2; 20 + canvas.height = Math.round(contentRect.height) * 2; 21 21 22 22 //Clear 23 23 ctx.clearRect(0, 0, canvas.width, canvas.height); ··· 64 64 ctx.restore(); 65 65 } 66 66 } 67 - 68 67 </script> 69 68 70 69 <canvas bind:this={canvas} bind:contentRect class="w-full h-full"></canvas>
+7 -8
src/lib/visualizations/CircleCirclesVisualizer.svelte src/lib/visualizations/core/CircleCirclesVisualizer.svelte
··· 1 1 <script lang="ts"> 2 - export let values:Float32Array; 2 + export let values: Float32Array; 3 3 4 4 export let color: string | undefined = undefined; 5 5 export let startHue: number | undefined = undefined; ··· 10 10 export let varyBrightness = false; 11 11 12 12 let canvas: HTMLCanvasElement; 13 - let contentRect:DOMRectReadOnly; 13 + let contentRect: DOMRectReadOnly; 14 14 15 - $:if(canvas && contentRect){ 15 + $: if (canvas && contentRect) { 16 16 const ctx = canvas.getContext('2d')!; 17 17 18 18 //Update canvas size 19 - canvas.width = Math.round(contentRect.width); 20 - canvas.height = Math.round(contentRect.height); 19 + canvas.width = Math.round(contentRect.width) * 2; 20 + canvas.height = Math.round(contentRect.height) * 2; 21 21 22 22 //Clear 23 23 ctx.clearRect(0, 0, canvas.width, canvas.height); ··· 69 69 70 70 ctx.restore(); 71 71 } 72 - }; 73 - 72 + } 74 73 </script> 75 74 76 - <canvas bind:this={canvas} bind:contentRect class="w-full h-full"></canvas> 75 + <canvas bind:this={canvas} bind:contentRect class="w-full h-full"></canvas>
+6 -7
src/lib/visualizations/DeformedCircleVisualizer.svelte src/lib/visualizations/core/DeformedCircleVisualizer.svelte
··· 1 1 <script lang="ts"> 2 - export let values:Float32Array; 2 + export let values: Float32Array; 3 3 4 4 export let color: string | undefined = undefined; 5 5 export let startHue: number | undefined = undefined; ··· 8 8 export let maxRadius: number = 0.4; 9 9 10 10 let canvas: HTMLCanvasElement; 11 - let contentRect:DOMRectReadOnly; 11 + let contentRect: DOMRectReadOnly; 12 12 13 - $:if(canvas && contentRect){ 13 + $: if (canvas && contentRect) { 14 14 const ctx = canvas.getContext('2d')!; 15 15 16 16 //Update canvas size 17 - canvas.width = Math.round(contentRect.width); 18 - canvas.height = Math.round(contentRect.height); 17 + canvas.width = Math.round(contentRect.width) * 2; 18 + canvas.height = Math.round(contentRect.height) * 2; 19 19 20 20 //Clear 21 21 ctx.clearRect(0, 0, canvas.width, canvas.height); ··· 60 60 } 61 61 62 62 ctx.fill(); 63 - }; 64 - 63 + } 65 64 </script> 66 65 67 66 <canvas bind:this={canvas} bind:contentRect style="filter: blur(24px);" class="w-full h-full"
+1 -1
src/lib/visualizations/Glow.svelte src/lib/visualizations/core/Glow.svelte
··· 11 11 </svg> 12 12 <div class="w-full h-full" style="filter: url(#blur);"> 13 13 <slot /> 14 - </div> 14 + </div>
+11 -9
src/lib/visualizations/InnerGlowVisualizer.svelte src/lib/visualizations/core/InnerGlowVisualizer.svelte
··· 1 1 <script lang="ts"> 2 - export let values:Float32Array; 3 - 2 + export let values: Float32Array; 3 + 4 4 export let color: string | undefined = undefined; 5 5 export let startHue: number | undefined = undefined; 6 6 export let endHue: number | undefined = undefined; ··· 12 12 export let deformation = 10; 13 13 14 14 let canvas: HTMLCanvasElement; 15 - let contentRect:DOMRectReadOnly; 15 + let contentRect: DOMRectReadOnly; 16 16 17 - $:if(canvas && contentRect){ 17 + $: if (canvas && contentRect) { 18 18 const ctx = canvas.getContext('2d')!; 19 19 20 20 //Update canvas size 21 - canvas.width = Math.round(contentRect.width); 22 - canvas.height = Math.round(contentRect.height); 21 + canvas.width = Math.round(contentRect.width) * 2; 22 + canvas.height = Math.round(contentRect.height) * 2; 23 23 24 24 //Clear 25 25 ctx.clearRect(0, 0, canvas.width, canvas.height); ··· 63 63 } 64 64 ctx.fill(); 65 65 66 - 67 66 // bottom side 68 67 if (color) ctx.fillStyle = color; 69 68 else if (colorBottomLeft && colorBottomRight) { ··· 79 78 ctx.lineTo(0, canvas.height); 80 79 for (let i = 0; i < values.length; i++) { 81 80 const amplitude = values[i]; 82 - ctx.lineTo(canvas.width * (i / values.length), canvas.height - (amplitude * deformation + sideVisible)); 81 + ctx.lineTo( 82 + canvas.width * (i / values.length), 83 + canvas.height - (amplitude * deformation + sideVisible) 84 + ); 83 85 } 84 86 ctx.fill(); 85 87 ··· 124 126 ctx.lineTo(canvas.width * (1 - i / values.length), amplitude * deformation + sideVisible); 125 127 } 126 128 ctx.fill(); 127 - }; 129 + } 128 130 </script> 129 131 130 132 <canvas bind:this={canvas} bind:contentRect style="filter: blur(12px)" class="w-full h-full"
+2 -2
src/lib/visualizations/MicrophoneVisualizer.svelte src/lib/visualizations/core/MicrophoneVisualizer.svelte
··· 1 1 <script lang="ts"> 2 - export let value:number; 2 + export let value: number; 3 3 4 4 export let color: string | undefined = '#f59e0b'; 5 5 export let backgroundColor: string | undefined = '#78350f'; ··· 24 24 d="M6 10.5a.75.75 0 0 1 .75.75v1.5a5.25 5.25 0 1 0 10.5 0v-1.5a.75.75 0 0 1 1.5 0v1.5a6.751 6.751 0 0 1-6 6.709v2.291h3a.75.75 0 0 1 0 1.5h-7.5a.75.75 0 0 1 0-1.5h3v-2.291a6.751 6.751 0 0 1-6-6.709v-1.5A.75.75 0 0 1 6 10.5Z" 25 25 fill={color} 26 26 /> 27 - </svg> 27 + </svg>
+2 -2
src/lib/visualizations/SpeakerVisualizer.svelte src/lib/visualizations/core/SpeakerVisualizer.svelte
··· 1 1 <script lang="ts"> 2 - export let value:number; 2 + export let value: number; 3 3 4 4 export let color: string | undefined = '#f59e0b'; 5 5 export let backgroundColor: string | undefined = '#78350f'; ··· 33 33 fill={accentColor} 34 34 mask="url(#speaker-mask-horizontal)" 35 35 /> 36 - </svg> 36 + </svg>
+16
src/lib/visualizations/audio/AudioFrequency.svelte
··· 1 + <script lang="ts"> 2 + import type { WavRecorder, AudioFilePlayer, WavStreamPlayer } from '$lib/visualizations/wavtools'; 3 + import { raf, normalizeArray } from '../core/utils'; 4 + 5 + export let audio: AudioFilePlayer | WavRecorder | WavStreamPlayer | null; 6 + 7 + let values: Float32Array = new Float32Array([0]); 8 + 9 + //Update frequency values every render frame 10 + raf(() => (values = audio ? audio.getFrequencies('music').values : new Float32Array([0]))); 11 + 12 + //Recreate the getValues function when values changes (to trigger reactivity) 13 + $: getValues = (detail: number) => normalizeArray(values, detail); 14 + </script> 15 + 16 + <slot {values} {getValues} />
+16
src/lib/visualizations/audio/BarAudioVisualizer.svelte
··· 1 + <script lang="ts"> 2 + import type { WavRecorder, AudioFilePlayer, WavStreamPlayer } from '$lib/visualizations/wavtools'; 3 + import AudioFrequency from './AudioFrequency.svelte'; 4 + import Glow from '../core/Glow.svelte'; 5 + import BarVisualizer from '../core/BarVisualizer.svelte'; 6 + 7 + export let audio: AudioFilePlayer | WavRecorder | WavStreamPlayer | null; 8 + export let glow: number | undefined = 3; 9 + export let detail: number | undefined = 50; 10 + </script> 11 + 12 + <AudioFrequency {audio} let:getValues> 13 + <Glow {glow}> 14 + <BarVisualizer values={getValues(detail || 50)} {...$$restProps} /> 15 + </Glow> 16 + </AudioFrequency>
+16
src/lib/visualizations/audio/CircleBarAudioVisualizer.svelte
··· 1 + <script lang="ts"> 2 + import type { WavRecorder, AudioFilePlayer, WavStreamPlayer } from '$lib/visualizations/wavtools'; 3 + import AudioFrequency from './AudioFrequency.svelte'; 4 + import Glow from '../core/Glow.svelte'; 5 + import CircleBarVisualizer from '../core/CircleBarVisualizer.svelte'; 6 + 7 + export let audio: AudioFilePlayer | WavRecorder | WavStreamPlayer | null; 8 + export let glow: number | undefined = 3; 9 + export let detail: number | undefined = 50; 10 + </script> 11 + 12 + <AudioFrequency {audio} let:getValues> 13 + <Glow {glow}> 14 + <CircleBarVisualizer values={getValues(detail || 50)} {...$$restProps} /> 15 + </Glow> 16 + </AudioFrequency>
+16
src/lib/visualizations/audio/CircleCirclesAudioVisualizer.svelte
··· 1 + <script lang="ts"> 2 + import type { WavRecorder, AudioFilePlayer, WavStreamPlayer } from '$lib/visualizations/wavtools'; 3 + import AudioFrequency from './AudioFrequency.svelte'; 4 + import Glow from '../core/Glow.svelte'; 5 + import CircleCirclesVisualizer from '../core/CircleCirclesVisualizer.svelte'; 6 + 7 + export let audio: AudioFilePlayer | WavRecorder | WavStreamPlayer | null; 8 + export let glow: number | undefined = 3; 9 + export let detail: number | undefined = 50; 10 + </script> 11 + 12 + <AudioFrequency {audio} let:getValues> 13 + <Glow {glow}> 14 + <CircleCirclesVisualizer values={getValues(detail || 50)} {...$$restProps} /> 15 + </Glow> 16 + </AudioFrequency>
+16
src/lib/visualizations/audio/DeformedCircleAudioVisualizer.svelte
··· 1 + <script lang="ts"> 2 + import type { WavRecorder, AudioFilePlayer, WavStreamPlayer } from '$lib/visualizations/wavtools'; 3 + import AudioFrequency from './AudioFrequency.svelte'; 4 + import Glow from '../core/Glow.svelte'; 5 + import DeformedCircleVisualizer from '../core/DeformedCircleVisualizer.svelte'; 6 + 7 + export let audio: AudioFilePlayer | WavRecorder | WavStreamPlayer | null; 8 + export let glow: number | undefined = 20; 9 + export let detail: number | undefined = 50; 10 + </script> 11 + 12 + <AudioFrequency {audio} let:getValues> 13 + <Glow {glow}> 14 + <DeformedCircleVisualizer values={getValues(detail || 50)} {...$$restProps} /> 15 + </Glow> 16 + </AudioFrequency>
+16
src/lib/visualizations/audio/InnerGlowAudioVisualizer.svelte
··· 1 + <script lang="ts"> 2 + import type { WavRecorder, AudioFilePlayer, WavStreamPlayer } from '$lib/visualizations/wavtools'; 3 + import AudioFrequency from './AudioFrequency.svelte'; 4 + import Glow from '../core/Glow.svelte'; 5 + import InnerGlowVisualizer from '../core/InnerGlowVisualizer.svelte'; 6 + 7 + export let audio: AudioFilePlayer | WavRecorder | WavStreamPlayer | null; 8 + export let glow: number | undefined = 10; 9 + export let detail: number | undefined = 50; 10 + </script> 11 + 12 + <AudioFrequency {audio} let:getValues> 13 + <Glow {glow}> 14 + <InnerGlowVisualizer values={getValues(detail || 50)} {...$$restProps} /> 15 + </Glow> 16 + </AudioFrequency>
+15
src/lib/visualizations/audio/MicrophoneAudioVisualizer.svelte
··· 1 + <script lang="ts"> 2 + import type { WavRecorder, AudioFilePlayer, WavStreamPlayer } from '$lib/visualizations/wavtools'; 3 + import AudioFrequency from './AudioFrequency.svelte'; 4 + import Glow from '../core/Glow.svelte'; 5 + import MicrophoneVisualizer from '../core/MicrophoneVisualizer.svelte'; 6 + 7 + export let audio: AudioFilePlayer | WavRecorder | WavStreamPlayer | null; 8 + export let glow: number | undefined = 3; 9 + </script> 10 + 11 + <AudioFrequency {audio} let:getValues> 12 + <Glow {glow}> 13 + <MicrophoneVisualizer value={getValues(1)[0]} {...$$restProps} /> 14 + </Glow> 15 + </AudioFrequency>
+15
src/lib/visualizations/audio/SpeakerAudioVisualizer.svelte
··· 1 + <script lang="ts"> 2 + import type { WavRecorder, AudioFilePlayer, WavStreamPlayer } from '$lib/visualizations/wavtools'; 3 + import AudioFrequency from './AudioFrequency.svelte'; 4 + import Glow from '../core/Glow.svelte'; 5 + import SpeakerVisualizer from '../core/SpeakerVisualizer.svelte'; 6 + 7 + export let audio: AudioFilePlayer | WavRecorder | WavStreamPlayer | null; 8 + export let glow: number | undefined = 3; 9 + </script> 10 + 11 + <AudioFrequency {audio} let:getValues> 12 + <Glow {glow}> 13 + <SpeakerVisualizer value={getValues(1)[0]} {...$$restProps} /> 14 + </Glow> 15 + </AudioFrequency>
-17
src/lib/visualizations/raf.ts
··· 1 - import { onMount } from "svelte"; 2 - 3 - export async function raf(callback:()=>void){ 4 - 5 - let mounted = true; 6 - 7 - async function render(){ 8 - if(!mounted)return; 9 - callback(); 10 - requestAnimationFrame(render); 11 - } 12 - 13 - onMount(()=>{ 14 - render(); 15 - return ()=>mounted = false; 16 - }) 17 - }
+17
src/lib/visualizations/wav_helper.ts src/lib/visualizations/core/utils.ts
··· 1 1 const dataMap = new WeakMap(); 2 2 3 + import { onMount } from 'svelte'; 4 + 5 + export async function raf(callback: () => void) { 6 + let mounted = true; 7 + 8 + async function render() { 9 + if (!mounted) return; 10 + callback(); 11 + requestAnimationFrame(render); 12 + } 13 + 14 + onMount(() => { 15 + render(); 16 + return () => (mounted = false); 17 + }); 18 + } 19 + 3 20 /** 4 21 * Normalizes a Float32Array to Array(m): We use this to draw amplitudes on a graph 5 22 * If we're rendering the same audio data, then we'll often be using
+58 -93
src/routes/+page.svelte
··· 1 1 <script lang="ts"> 2 - import BarVisualizer from '$lib/visualizations/BarVisualizer.svelte'; 3 - import CircleBarVisualizer from '$lib/visualizations/CircleBarVisualizer.svelte'; 4 - import CircleCirclesVisualizer from '$lib/visualizations/CircleCirclesVisualizer.svelte'; 5 - import DeformedCircleVisualizer from '$lib/visualizations/DeformedCircleVisualizer.svelte'; 6 - import InnerGlowVisualizer from '$lib/visualizations/InnerGlowVisualizer.svelte'; 7 - import MicrophoneVisualizer from '$lib/visualizations/MicrophoneVisualizer.svelte'; 8 - import SpeakerVisualizer from '$lib/visualizations/SpeakerVisualizer.svelte'; 9 - import Glow from '$lib/visualizations/Glow.svelte'; 10 - import AudioFrequency from '$lib/visualizations/AudioFrequency.svelte'; 2 + import DeformedCircleVisualizer from '$lib/visualizations/core/DeformedCircleVisualizer.svelte'; 3 + import InnerGlowVisualizer from '$lib/visualizations/core/InnerGlowVisualizer.svelte'; 4 + import MicrophoneVisualizer from '$lib/visualizations/core/MicrophoneVisualizer.svelte'; 5 + import SpeakerVisualizer from '$lib/visualizations/core/SpeakerVisualizer.svelte'; 6 + import Glow from '$lib/visualizations/core/Glow.svelte'; 7 + import AudioFrequency from '$lib/visualizations/audio/AudioFrequency.svelte'; 11 8 import { WavRecorder, AudioFilePlayer } from '$lib/visualizations/wavtools'; 12 - import CircleBarAudioVisualizer from '$lib/visualizations/CircleBarAudioVisualizer.svelte'; 9 + 10 + import CircleBarAudioVisualizer from '$lib/visualizations/audio/CircleBarAudioVisualizer.svelte'; 11 + import BarAudioVisualizer from '$lib/visualizations/audio/BarAudioVisualizer.svelte'; 12 + import CircleCirclesAudioVisualizer from '$lib/visualizations/audio/CircleCirclesAudioVisualizer.svelte'; 13 13 14 14 let audio: WavRecorder | AudioFilePlayer | null = null; 15 15 let state: 'recording' | 'music' | null = null; 16 16 17 17 //Stop playing music, if wrong state 18 - $:if(state !== 'music' && audio instanceof WavRecorder){ 18 + $: if (state !== 'music' && audio instanceof WavRecorder) { 19 19 audio.end(); 20 20 audio = null; 21 21 } 22 22 23 23 //Stop recording, if wrong state 24 - $:if(state !== 'recording' && audio instanceof AudioFilePlayer){ 24 + $: if (state !== 'recording' && audio instanceof AudioFilePlayer) { 25 25 audio.stop(); 26 26 audio = null; 27 27 } 28 28 29 29 //Start playing music, if not playing already 30 - $:if(state == 'music' && !audio){ 31 - let player = audio = new AudioFilePlayer(); 32 - audio.loadFile('/svelte-audio-visualizations/music.mp3').then(()=>player.play()); 30 + $: if (state == 'music' && !audio) { 31 + let player = (audio = new AudioFilePlayer()); 32 + audio.loadFile('/svelte-audio-visualizations/music.mp3').then(() => player.play()); 33 33 } 34 34 35 35 //Start recording, if not recording already 36 - $:if(state == 'recording' && !audio){ 37 - let recorder = audio = new WavRecorder({ sampleRate: 24000 }); 38 - audio.begin().then(()=>recorder.record()); 36 + $: if (state == 'recording' && !audio) { 37 + let recorder = (audio = new WavRecorder({ sampleRate: 24000 })); 38 + audio.begin().then(() => recorder.record()); 39 39 } 40 - 41 40 </script> 42 41 43 - <!-- Example of creating a higher order component, that combines --> 44 - <div style="width:300px;height:300px;"> 45 - <CircleBarAudioVisualizer 46 - {audio} 47 - startHue={0} 48 - endHue={50} 49 - rotate={2} 50 - /> 51 - </div> 42 + <div class="mx-auto px-4 max-w-4xl w-full py-8 sm:py-24"> 43 + <div class="flex justify-between"> 44 + <div class="flex gap-2 flex-col sm:flex-row"> 45 + <button 46 + type="button" 47 + on:click={() => (state = state == 'recording' ? null : 'recording')} 48 + class="rounded-full px-3 py-2 text-sm font-semibold focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-amber-500 {state === 49 + 'recording' 50 + ? 'text-stone-500 bg-stone-500/10 border border-stone-500/20 hover:bg-stone-500/20' 51 + : 'text-amber-500 bg-amber-500/10 border border-amber-500/20 hover:bg-amber-500/20'}" 52 + >{state === 'recording' ? 'stop ' : 'start '}microphone</button 53 + > 54 + <button 55 + type="button" 56 + on:click={() => (state = state == 'music' ? null : 'music')} 57 + class="rounded-full px-3 py-2 text-sm font-semibold focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-amber-500 {state === 58 + 'music' 59 + ? 'text-stone-500 bg-stone-500/10 border border-stone-500/20 hover:bg-stone-500/20' 60 + : 'text-amber-500 bg-amber-500/10 border border-amber-500/20 hover:bg-amber-500/20'}" 61 + >{state === 'music' ? 'stop ' : 'start '}music</button 62 + > 63 + </div> 64 + <div class="text-stone-500 text-sm font-semibold"> 65 + made by <a href="https://flo-bit.dev/" class="text-amber-600">flo-bit</a> 66 + </div> 67 + </div> 52 68 53 - <AudioFrequency {audio} let:getValues > 54 - <div class="mx-auto px-4 max-w-4xl w-full py-24"> 55 - <div> 56 - <div> 57 - <button 58 - type="button" 59 - on:click={()=>state = state == 'recording' ? null : 'recording'} 60 - class="rounded-full px-3 py-2 text-sm font-semibold focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-amber-500 {state === 61 - 'recording' 62 - ? 'text-stone-500 bg-stone-500/10 border border-stone-500/20 hover:bg-stone-500/20' 63 - : 'text-amber-500 bg-amber-500/10 border border-amber-500/20 hover:bg-amber-500/20'}" 64 - >{state === 'recording' ? 'stop ' : 'start '}microphone</button 65 - > 66 - <button 67 - type="button" 68 - on:click={()=>state = state == 'music' ? null : "music"} 69 - class="rounded-full px-3 py-2 text-sm font-semibold focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-amber-500 {state === 70 - 'music' 71 - ? 'text-stone-500 bg-stone-500/10 border border-stone-500/20 hover:bg-stone-500/20' 72 - : 'text-amber-500 bg-amber-500/10 border border-amber-500/20 hover:bg-amber-500/20'}" 73 - >{state === 'music' ? 'stop ' : 'start '}music</button 74 - > 75 - </div> 76 - <div class="text-stone-500 text-sm font-semibold"> 77 - made by <a href="https://flo-bit.dev/" class="text-amber-600">flo-bit</a> 78 - </div> 69 + <div class="grid grid-cols-1 sm:grid-cols-3 gap-4 mt-8"> 70 + <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 71 + <CircleBarAudioVisualizer {audio} startHue={0} endHue={50} rotate={2} /> 72 + </div> 73 + <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 74 + <BarAudioVisualizer {audio} barSpacing={8} startHue={0} endHue={50} center /> 79 75 </div> 80 76 81 - <div class="grid grid-cols-1 sm:grid-cols-3 gap-4 mt-8"> 82 - <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 83 - <Glow> 84 - <CircleBarVisualizer 85 - values={getValues(50)} 86 - startHue={0} 87 - endHue={50} 88 - rotate={2} 89 - /> 90 - </Glow> 91 - </div> 92 - <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 93 - <Glow> 94 - <BarVisualizer 95 - values={getValues(16)} 96 - barSpacing={8} 97 - startHue={0} 98 - endHue={50} 99 - center 100 - /> 101 - </Glow> 102 - </div> 77 + <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 78 + <CircleCirclesAudioVisualizer {audio} startHue={0} endHue={50} /> 79 + </div> 103 80 104 - <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 105 - <Glow> 106 - <CircleCirclesVisualizer 107 - values={getValues(50)} 108 - startHue={0} 109 - endHue={50} 110 - /> 111 - </Glow> 112 - </div> 81 + <AudioFrequency {audio} let:getValues> 113 82 <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 114 83 <Glow glow={20}> 115 - <DeformedCircleVisualizer 116 - values={getValues(16)} 117 - startHue={0} 118 - endHue={50} 119 - /> 84 + <DeformedCircleVisualizer values={getValues(16)} startHue={0} endHue={50} /> 120 85 </Glow> 121 86 </div> 122 87 <div class="h-64 w-full rounded-xl border border-white/15 overflow-hidden"> 123 88 <Glow glow={10}> 124 - <InnerGlowVisualizer values={getValues(8)} startHue={0} endHue={50} /> 89 + <InnerGlowVisualizer values={getValues(32)} startHue={0} endHue={50} /> 125 90 </Glow> 126 91 </div> 127 92 <div ··· 134 99 <SpeakerVisualizer value={getValues(1)[0]} /> 135 100 </div> 136 101 </div> 137 - </div> 102 + </AudioFrequency> 138 103 </div> 139 - </AudioFrequency> 104 + </div>