11import * as twgl from '../../../js/twgl-full.module.js' ;
2- import ByteBeatNode from '../../../src/ByteBeatNode.js' ;
32import { drawEffect } from './effect-utils.js' ;
43
54const colorBlue = new Float32Array ( [ 0 , 0 , 1 , 1 ] ) ;
65const colorGray = new Float32Array ( [ 0.25 , 0.25 , 0.25 , 1 ] ) ;
76
7+ const kChunkSize = 1024 ;
8+
89export default class DataEffect {
910 constructor ( gl ) {
1011 this . programInfo = twgl . createProgramInfo ( gl , [
@@ -52,24 +53,17 @@ export default class DataEffect {
5253 wrap : gl . CLAMP_TO_EDGE ,
5354 } ) ,
5455 ] ;
56+ this . dataCursor = 0 ;
57+ this . data = [ ] ;
5558 }
5659 reset ( gl ) {
57- this . dataTime = 0 ;
58- this . dataPos = 0 ;
5960 for ( let i = 0 ; i < this . dataWidth ; ++ i ) {
6061 this . dataBuf [ i ] = 0 ;
6162 }
62- for ( const tex of this . dataTex ) {
63- gl . bindTexture ( gl . TEXTURE_2D , tex ) ;
64- gl . texImage2D (
65- gl . TEXTURE_2D , 0 , gl . LUMINANCE , this . dataWidth , 1 , 0 ,
66- gl . LUMINANCE , gl . UNSIGNED_BYTE , this . dataBuf ) ;
67- }
63+ this . resize ( gl ) ;
6864 }
69- resize ( gl ) {
70- this . dataContext = ByteBeatNode . createContext ( ) ;
71- this . dataStack = ByteBeatNode . createStack ( ) ;
7265
66+ async resize ( gl ) {
7367 this . dataWidth = gl . drawingBufferWidth ;
7468 const dataBuf = new Uint8Array ( this . dataWidth ) ;
7569 this . dataPos = 0 ;
@@ -82,15 +76,74 @@ export default class DataEffect {
8276 }
8377 this . dataBuf = dataBuf ;
8478 this . dataTime = 0 ;
79+ this . oldDataTime = 0 ;
80+ this . data = new Map ( ) ;
81+ this . state = 'init' ;
82+ }
8583
84+ async #getData( byteBeat ) {
85+ this . updating = true ;
86+ const start = Math . ceil ( this . dataTime / kChunkSize ) * kChunkSize ;
87+ const numChannels = byteBeat . getNumChannels ( ) ;
88+ const dataP = [ ] ;
89+ for ( let channel = 0 ; channel < numChannels ; ++ channel ) {
90+ dataP . push ( byteBeat . getSamplesForTimeRange ( start , start + kChunkSize , 1 , this . dataContext , this . dataStack , channel ) ) ;
91+ }
92+ const data = await Promise . all ( dataP ) ;
93+ const chunkId = start / kChunkSize ;
94+ this . data . set ( chunkId , data ) ;
95+ this . updating = false ;
8696 }
97+
98+ #update( byteBeat ) {
99+ const noData = this . data . length === 0 ;
100+ const passingHalfWayPoint = ( this . oldDataTime % kChunkSize ) < kChunkSize / 2 && ( this . dataTime % kChunkSize ) >= kChunkSize / 2 ;
101+ const passingChunk = ( this . oldDataTime % kChunkSize ) === kChunkSize - 1 && this . dataTime % kChunkSize === 0 ;
102+ const oldChunkId = this . oldDataTime / kChunkSize | 0 ;
103+ this . oldDataTime = this . dataTime ;
104+ if ( passingChunk ) {
105+ this . data . delete ( oldChunkId ) ;
106+ }
107+ if ( ! this . updating && ( noData || passingHalfWayPoint ) ) {
108+ this . #getData( byteBeat ) ;
109+ }
110+ }
111+
112+ async #init( byteBeat ) {
113+ if ( this . dataContext ) {
114+ byteBeat . destroyContext ( this . dataContext ) ;
115+ byteBeat . destroyStack ( this . dataStack ) ;
116+ }
117+ this . dataContext = await byteBeat . createContext ( ) ;
118+ this . dataStack = await byteBeat . createStack ( ) ;
119+ await this . #getData( byteBeat ) ;
120+ this . state = 'running' ;
121+ }
122+
87123 render ( gl , commonUniforms , byteBeat ) {
124+ if ( this . state === 'init' ) {
125+ this . state = 'initializing' ;
126+ this . #init( byteBeat ) ;
127+ }
128+ if ( this . state !== 'running' ) {
129+ return ;
130+ }
131+ this . #update( byteBeat ) ;
88132 const numChannels = byteBeat . getNumChannels ( ) ;
89133
90134 const { uniforms, programInfo, bufferInfo} = this ;
91135
136+ const chunkId = this . dataTime / kChunkSize | 0 ;
137+ const chunk = this . data . get ( chunkId ) ;
138+ const ndx = this . dataTime % kChunkSize ;
92139 for ( let channel = 0 ; channel < numChannels ; ++ channel ) {
93- this . dataPixel [ 0 ] = Math . round ( byteBeat . getSampleForTime ( this . dataTime ++ , this . dataContext , this . dataStack , channel ) * 127 ) + 127 ;
140+ try {
141+ const ch = chunk [ channel ] ;
142+ const sample = ch [ ndx ] ;
143+ this . dataPixel [ 0 ] = Math . round ( sample * 127 ) + 127 ;
144+ } catch {
145+ //
146+ }
94147 gl . bindTexture ( gl . TEXTURE_2D , this . dataTex [ channel ] ) ;
95148 gl . texSubImage2D ( gl . TEXTURE_2D , 0 , this . dataPos , 0 , 1 , 1 , gl . LUMINANCE , gl . UNSIGNED_BYTE , this . dataPixel ) ;
96149 this . dataPos = ( this . dataPos + 1 ) % this . dataWidth ;
@@ -107,5 +160,6 @@ export default class DataEffect {
107160 gl . disable ( gl . BLEND ) ;
108161 }
109162 }
163+ ++ this . dataTime ;
110164 }
111165}
0 commit comments