|
35 | 35 | import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; |
36 | 36 |
|
37 | 37 | let camera, scene, renderer; |
38 | | - let computeNode, computeResetNode; |
| 38 | + let computeNode; |
39 | 39 | let waveBuffer, sampleRate; |
40 | | - let waveArray, originalWaveBuffer; |
| 40 | + let waveArray; |
41 | 41 | let currentAudio, currentAnalyser; |
42 | 42 | const analyserBuffer = new Uint8Array( 1024 ); |
43 | 43 | let analyserTexture; |
|
49 | 49 |
|
50 | 50 | if ( currentAudio ) currentAudio.stop(); |
51 | 51 |
|
52 | | - await renderer.computeAsync( computeResetNode ); |
53 | 52 | // compute audio |
| 53 | + |
54 | 54 | await renderer.computeAsync( computeNode ); |
| 55 | + |
55 | 56 | const wave = new Float32Array( await renderer.getArrayBufferAsync( waveArray.value ) ); |
56 | 57 |
|
57 | 58 | // play result |
|
93 | 94 |
|
94 | 95 | // adding extra silence to delay and pitch |
95 | 96 | waveBuffer = new Float32Array( [ ...waveBuffer, ...new Float32Array( 200000 ) ] ); |
96 | | - originalWaveBuffer = waveBuffer.slice(); |
97 | | - |
| 97 | + |
98 | 98 | sampleRate = audioBuffer.sampleRate / audioBuffer.numberOfChannels; |
99 | 99 |
|
100 | 100 | // create webgpu buffers |
101 | 101 |
|
102 | 102 | waveArray = instancedArray( waveBuffer ); |
103 | | - const originalWave = instancedArray( originalWaveBuffer ).toReadOnly(); |
| 103 | + |
| 104 | + // read-only buffer |
| 105 | + |
| 106 | + const originalWave = instancedArray( waveBuffer ).toReadOnly(); |
104 | 107 |
|
105 | 108 | // The Pixel Buffer Object (PBO) is required to get the GPU computed data to the CPU in the WebGL2 fallback. |
106 | 109 | // As used in `renderer.getArrayBufferAsync( waveArray.value )`. |
107 | 110 |
|
| 111 | + originalWave.setPBO( true ); |
108 | 112 | waveArray.setPBO( true ); |
109 | 113 |
|
110 | 114 | // params |
|
114 | 118 | const delayOffset = uniform( .55 ); |
115 | 119 |
|
116 | 120 |
|
117 | | - // compute |
| 121 | + // compute (shader-node) |
118 | 122 |
|
119 | | - computeNode = Fn( () => { |
| 123 | + const computeShaderFn = Fn( () => { |
120 | 124 |
|
121 | 125 | const index = float( instanceIndex ); |
122 | 126 |
|
123 | 127 | // pitch |
124 | 128 |
|
125 | 129 | const time = index.mul( pitch ); |
126 | 130 |
|
127 | | - let wave = waveArray.element( time ); |
| 131 | + let wave = originalWave.element( time ); |
128 | 132 |
|
129 | 133 |
|
130 | 134 | // delay |
131 | 135 |
|
132 | 136 | for ( let i = 1; i < 7; i ++ ) { |
133 | 137 |
|
134 | | - const waveOffset = waveArray.element( index.sub( delayOffset.mul( sampleRate ).mul( i ) ).mul( pitch ) ); |
| 138 | + const waveOffset = originalWave.element( index.sub( delayOffset.mul( sampleRate ).mul( i ) ).mul( pitch ) ); |
135 | 139 | const waveOffsetVolume = waveOffset.mul( delayVolume.div( i * i ) ); |
136 | 140 |
|
137 | 141 | wave = wave.add( waveOffsetVolume ); |
|
145 | 149 |
|
146 | 150 | waveStorageElementNode.assign( wave ); |
147 | 151 |
|
148 | | - } )().compute( waveBuffer.length ); |
| 152 | + } ); |
149 | 153 |
|
150 | | - computeResetNode = Fn( () => { |
151 | 154 |
|
152 | | - waveArray.element( instanceIndex ).assign( originalWave.element( instanceIndex ) ); |
153 | | - |
154 | | - } )().compute( waveBuffer.length ); |
| 155 | + // compute |
155 | 156 |
|
| 157 | + computeNode = computeShaderFn().compute( waveBuffer.length ); |
156 | 158 |
|
157 | 159 |
|
158 | 160 | // gui |
|
194 | 196 | container.appendChild( renderer.domElement ); |
195 | 197 |
|
196 | 198 | window.addEventListener( 'resize', onWindowResize ); |
| 199 | + document.addEventListener( 'click', playAudioBuffer ); |
197 | 200 |
|
198 | 201 | playAudioBuffer(); |
199 | 202 |
|
200 | | - // on click replay |
201 | | - renderer.domElement.addEventListener( 'click', playAudioBuffer ); |
202 | | - |
203 | 203 | } |
204 | 204 |
|
205 | 205 | function onWindowResize() { |
|
0 commit comments