|
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