1
1
import * as twgl from '../../../js/twgl-full.module.js' ;
2
- import ByteBeatNode from '../../../src/ByteBeatNode.js' ;
3
2
import { drawEffect } from './effect-utils.js' ;
4
3
5
4
const colorBlue = new Float32Array ( [ 0 , 0 , 1 , 1 ] ) ;
6
5
const colorGray = new Float32Array ( [ 0.25 , 0.25 , 0.25 , 1 ] ) ;
7
6
7
+ const kChunkSize = 1024 ;
8
+
8
9
export default class DataEffect {
9
10
constructor ( gl ) {
10
11
this . programInfo = twgl . createProgramInfo ( gl , [
@@ -52,24 +53,17 @@ export default class DataEffect {
52
53
wrap : gl . CLAMP_TO_EDGE ,
53
54
} ) ,
54
55
] ;
56
+ this . dataCursor = 0 ;
57
+ this . data = [ ] ;
55
58
}
56
59
reset ( gl ) {
57
- this . dataTime = 0 ;
58
- this . dataPos = 0 ;
59
60
for ( let i = 0 ; i < this . dataWidth ; ++ i ) {
60
61
this . dataBuf [ i ] = 0 ;
61
62
}
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 ) ;
68
64
}
69
- resize ( gl ) {
70
- this . dataContext = ByteBeatNode . createContext ( ) ;
71
- this . dataStack = ByteBeatNode . createStack ( ) ;
72
65
66
+ async resize ( gl ) {
73
67
this . dataWidth = gl . drawingBufferWidth ;
74
68
const dataBuf = new Uint8Array ( this . dataWidth ) ;
75
69
this . dataPos = 0 ;
@@ -82,15 +76,74 @@ export default class DataEffect {
82
76
}
83
77
this . dataBuf = dataBuf ;
84
78
this . dataTime = 0 ;
79
+ this . oldDataTime = 0 ;
80
+ this . data = new Map ( ) ;
81
+ this . state = 'init' ;
82
+ }
85
83
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 ;
86
96
}
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
+
87
123
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 ) ;
88
132
const numChannels = byteBeat . getNumChannels ( ) ;
89
133
90
134
const { uniforms, programInfo, bufferInfo} = this ;
91
135
136
+ const chunkId = this . dataTime / kChunkSize | 0 ;
137
+ const chunk = this . data . get ( chunkId ) ;
138
+ const ndx = this . dataTime % kChunkSize ;
92
139
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
+ }
94
147
gl . bindTexture ( gl . TEXTURE_2D , this . dataTex [ channel ] ) ;
95
148
gl . texSubImage2D ( gl . TEXTURE_2D , 0 , this . dataPos , 0 , 1 , 1 , gl . LUMINANCE , gl . UNSIGNED_BYTE , this . dataPixel ) ;
96
149
this . dataPos = ( this . dataPos + 1 ) % this . dataWidth ;
@@ -107,5 +160,6 @@ export default class DataEffect {
107
160
gl . disable ( gl . BLEND ) ;
108
161
}
109
162
}
163
+ ++ this . dataTime ;
110
164
}
111
165
}
0 commit comments