[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.

Move audio frequency to separate component

Robert Smith (Oct 13, 2024, 10:08 PM +0100) 81fbfa2d 4eb8c4b8

+114 -88
+96 -88
src/routes/+page.svelte
··· 3 3 import CircleBarVisualizer from '$lib/visualizations/CircleBarVisualizer.svelte'; 4 4 import CircleCirclesVisualizer from '$lib/visualizations/CircleCirclesVisualizer.svelte'; 5 5 import DeformedCircleVisualizer from '$lib/visualizations/DeformedCircleVisualizer.svelte'; 6 - import Glow from '$lib/visualizations/Glow.svelte'; 7 6 import InnerGlowVisualizer from '$lib/visualizations/InnerGlowVisualizer.svelte'; 8 7 import MicrophoneVisualizer from '$lib/visualizations/MicrophoneVisualizer.svelte'; 9 - import { raf } from '$lib/visualizations/raf'; 10 8 import SpeakerVisualizer from '$lib/visualizations/SpeakerVisualizer.svelte'; 11 - import { normalizeArray } from '$lib/visualizations/wav_helper'; 9 + import Glow from '$lib/visualizations/Glow.svelte'; 10 + import AudioFrequency from '$lib/visualizations/AudioFrequency.svelte'; 12 11 import { WavRecorder, AudioFilePlayer } from '$lib/visualizations/wavtools'; 12 + import BarAudioVisualizer from '$lib/visualizations/BarAudioVisualizer.svelte'; 13 13 14 14 let audio: WavRecorder | AudioFilePlayer | null = null; 15 15 let state: 'recording' | 'music' | null = null; 16 - let values:Float32Array = new Float32Array([0]); 17 16 18 17 //Stop playing music, if wrong state 19 18 $:if(state !== 'music' && audio instanceof WavRecorder){ ··· 39 38 audio.begin().then(()=>recorder.record()); 40 39 } 41 40 42 - //Update frequency values every render frame 43 - raf(() => values = audio ? audio.getFrequencies('music').values : new Float32Array([0])); 44 - 45 41 </script> 46 42 47 - <div class="mx-auto px-4 max-w-4xl w-full py-24"> 48 - <div> 49 - <div> 50 - <button 51 - type="button" 52 - on:click={()=>state = state == 'recording' ? null : 'recording'} 53 - 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 === 54 - 'recording' 55 - ? 'text-stone-500 bg-stone-500/10 border border-stone-500/20 hover:bg-stone-500/20' 56 - : 'text-amber-500 bg-amber-500/10 border border-amber-500/20 hover:bg-amber-500/20'}" 57 - >{state === 'recording' ? 'stop ' : 'start '}microphone</button 58 - > 59 - <button 60 - type="button" 61 - on:click={()=>state = state == 'music' ? null : "music"} 62 - 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 === 63 - 'music' 64 - ? 'text-stone-500 bg-stone-500/10 border border-stone-500/20 hover:bg-stone-500/20' 65 - : 'text-amber-500 bg-amber-500/10 border border-amber-500/20 hover:bg-amber-500/20'}" 66 - >{state === 'music' ? 'stop ' : 'start '}music</button 67 - > 68 - </div> 69 - </div> 70 - 71 - <div class="grid grid-cols-1 sm:grid-cols-3 gap-4 mt-8"> 72 - <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 73 - <Glow> 74 - <CircleBarVisualizer 75 - values={normalizeArray(values, 50)} 76 - startHue={0} 77 - endHue={50} 78 - rotate={2} 79 - /> 80 - </Glow> 81 - </div> 82 - <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 83 - <Glow> 84 - <BarVisualizer 85 - values={normalizeArray(values, 16)} 86 - barSpacing={8} 87 - startHue={0} 88 - endHue={50} 89 - center 90 - /> 91 - </Glow> 92 - </div> 93 - 94 - <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 95 - <Glow> 96 - <CircleCirclesVisualizer 97 - values={normalizeArray(values, 50)} 98 - startHue={0} 99 - endHue={50} 100 - /> 101 - </Glow> 102 - </div> 103 - <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 104 - <Glow glow={20}> 105 - <DeformedCircleVisualizer 106 - values={normalizeArray(values, 16)} 107 - startHue={0} 108 - endHue={50} 109 - /> 110 - </Glow> 111 - </div> 112 - <div class="h-64 w-full rounded-xl border border-white/15 overflow-hidden"> 113 - <Glow glow={10}> 114 - <InnerGlowVisualizer values={normalizeArray(values, 8)} startHue={0} endHue={50} /> 115 - </Glow> 116 - </div> 117 - <div 118 - class="h-64 w-full rounded-xl border border-white/15 overflow-hidden flex items-center justify-center gap-4" 119 - > 120 - <div class="size-20"> 121 - <MicrophoneVisualizer value={normalizeArray(values, 1)[0]} /> 122 - </div> 123 - <div class="size-20"> 124 - <SpeakerVisualizer value={normalizeArray(values, 1)[0]} /> 125 - </div> 126 - </div> 127 - </div> 43 + <!-- Example of creating a higher order component, that combines --> 44 + <div style="width:300px;height:300px;"> 45 + <BarAudioVisualizer 46 + {audio} 47 + startHue={0} 48 + endHue={50} 49 + rotate={2} 50 + /> 128 51 </div> 52 + 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> 77 + 78 + <div class="grid grid-cols-1 sm:grid-cols-3 gap-4 mt-8"> 79 + <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 80 + <Glow> 81 + <CircleBarVisualizer 82 + values={getValues(50)} 83 + startHue={0} 84 + endHue={50} 85 + rotate={2} 86 + /> 87 + </Glow> 88 + </div> 89 + <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 90 + <Glow> 91 + <BarVisualizer 92 + values={getValues(16)} 93 + barSpacing={8} 94 + startHue={0} 95 + endHue={50} 96 + center 97 + /> 98 + </Glow> 99 + </div> 100 + 101 + <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 102 + <Glow> 103 + <CircleCirclesVisualizer 104 + values={getValues(50)} 105 + startHue={0} 106 + endHue={50} 107 + /> 108 + </Glow> 109 + </div> 110 + <div class="h-64 w-full rounded-xl border border-white/15 p-4"> 111 + <Glow glow={20}> 112 + <DeformedCircleVisualizer 113 + values={getValues(16)} 114 + startHue={0} 115 + endHue={50} 116 + /> 117 + </Glow> 118 + </div> 119 + <div class="h-64 w-full rounded-xl border border-white/15 overflow-hidden"> 120 + <Glow glow={10}> 121 + <InnerGlowVisualizer values={getValues(8)} startHue={0} endHue={50} /> 122 + </Glow> 123 + </div> 124 + <div 125 + class="h-64 w-full rounded-xl border border-white/15 overflow-hidden flex items-center justify-center gap-4" 126 + > 127 + <div class="size-20"> 128 + <MicrophoneVisualizer value={getValues(1)[0]} /> 129 + </div> 130 + <div class="size-20"> 131 + <SpeakerVisualizer value={getValues(1)[0]} /> 132 + </div> 133 + </div> 134 + </div> 135 + </div> 136 + </AudioFrequency>
+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} />