@@ -53,6 +53,7 @@ function WaveformCanvas(props: {
5353 const { project } = useEditorContext ( ) ;
5454
5555 let canvas : HTMLCanvasElement | undefined ;
56+ let rafId : number | null = null ;
5657 const { width } = useSegmentContext ( ) ;
5758 const { secsPerPixel } = useTimelineContext ( ) ;
5859
@@ -65,11 +66,22 @@ function WaveformCanvas(props: {
6566 ) => {
6667 const maxAmplitude = h ;
6768
68- // yellow please
6969 ctx . fillStyle = color ;
7070 ctx . beginPath ( ) ;
7171
7272 const step = 0.05 / secsPerPixel ( ) ;
73+ const samplesPerSecond = 10 ;
74+
75+ const startTime = props . segment . start ;
76+ const endTime = props . segment . end ;
77+
78+ const pixelsPerSecond = 1 / secsPerPixel ( ) ;
79+ const samplesPerPixel = samplesPerSecond / pixelsPerSecond ;
80+
81+ let sampleStep = 0.1 ;
82+ if ( samplesPerPixel < 0.5 ) {
83+ sampleStep = Math . max ( 0.1 , Math . ceil ( 1 / samplesPerPixel ) * 0.1 ) ;
84+ }
7385
7486 ctx . moveTo ( 0 , h ) ;
7587
@@ -78,35 +90,39 @@ function WaveformCanvas(props: {
7890 return 1.0 - Math . max ( ww + gain , - 60 ) / - 60 ;
7991 } ;
8092
93+ let prevX = 0 ;
94+ let prevY = h ;
95+
8196 for (
82- let segmentTime = props . segment . start ;
83- segmentTime <= props . segment . end + 0.1 ;
84- segmentTime += 0.1
97+ let segmentTime = startTime ;
98+ segmentTime <= endTime + 0.1 ;
99+ segmentTime += sampleStep
85100 ) {
86- const index = Math . floor ( segmentTime * 10 ) ;
87- const xTime = index / 10 ;
101+ const index = Math . floor ( segmentTime * samplesPerSecond ) ;
102+ if ( index < 0 || index >= waveform . length ) continue ;
103+
104+ const xTime = index / samplesPerSecond ;
88105
89106 const currentDb =
90107 typeof waveform [ index ] === "number" ? waveform [ index ] : - 60 ;
91108 const amplitude = norm ( currentDb ) * maxAmplitude ;
92109
93- const x = ( xTime - props . segment . start ) / secsPerPixel ( ) ;
110+ const x = ( xTime - startTime ) / secsPerPixel ( ) ;
94111 const y = h - amplitude ;
95112
96- const prevX = ( xTime - 0.1 - props . segment . start ) / secsPerPixel ( ) ;
97- const prevDb =
98- typeof waveform [ index - 1 ] === "number" ? waveform [ index - 1 ] : - 60 ;
99- const prevAmplitude = norm ( prevDb ) * maxAmplitude ;
100- const prevY = h - prevAmplitude ;
101-
102- const cpX1 = prevX + step / 2 ;
103- const cpX2 = x - step / 2 ;
113+ if ( prevX !== x ) {
114+ const cpX1 = prevX + step / 2 ;
115+ const cpX2 = x - step / 2 ;
104116
105- ctx . bezierCurveTo ( cpX1 , prevY , cpX2 , y , x , y ) ;
117+ ctx . bezierCurveTo ( cpX1 , prevY , cpX2 , y , x , y ) ;
118+
119+ prevX = x ;
120+ prevY = y ;
121+ }
106122 }
107123
108124 ctx . lineTo (
109- ( props . segment . end + 0.3 - props . segment . start ) / secsPerPixel ( ) ,
125+ ( endTime + 0.3 - startTime ) / secsPerPixel ( ) ,
110126 h ,
111127 ) ;
112128
@@ -146,14 +162,25 @@ function WaveformCanvas(props: {
146162 }
147163
148164 createEffect ( ( ) => {
149- renderWaveforms ( ) ;
165+ // track reactive deps
166+ void width ( ) ;
167+ void secsPerPixel ( ) ;
168+ void project . audio . micVolumeDb ;
169+ void project . audio . systemVolumeDb ;
170+ if ( rafId !== null ) cancelAnimationFrame ( rafId ) ;
171+ rafId = requestAnimationFrame ( renderWaveforms ) ;
172+ } ) ;
173+
174+ onCleanup ( ( ) => {
175+ if ( rafId !== null ) cancelAnimationFrame ( rafId ) ;
150176 } ) ;
151177
152178 return (
153179 < canvas
154180 ref = { ( el ) => {
155181 canvas = el ;
156- renderWaveforms ( ) ;
182+ if ( rafId !== null ) cancelAnimationFrame ( rafId ) ;
183+ rafId = requestAnimationFrame ( renderWaveforms ) ;
157184 } }
158185 class = "absolute inset-0 w-full h-full pointer-events-none"
159186 height = { 52 }
0 commit comments