@@ -35,8 +35,10 @@ function strip(s) {
35
35
}
36
36
37
37
let g_context ;
38
+ let g_gainNode ;
38
39
let g_byteBeat ;
39
40
let g_filter ;
41
+ let g_localSettings ;
40
42
const g_analyzers = [ ] ;
41
43
let g_splitter ;
42
44
let g_merger ;
@@ -90,9 +92,11 @@ function reconnect() {
90
92
const lastNode = connectFor2Channels ( ) ;
91
93
if ( g_filter ) {
92
94
lastNode . connect ( g_filter ) ;
93
- g_filter . connect ( g_context . destination ) ;
95
+ g_filter . connect ( g_gainNode ) ;
96
+ g_gainNode . connect ( g_context . destination ) ;
94
97
} else {
95
- lastNode . connect ( g_context . destination ) ;
98
+ lastNode . connect ( g_gainNode ) ;
99
+ g_gainNode . connect ( g_context . destination ) ;
96
100
}
97
101
g_context . resume ( ) ;
98
102
}
@@ -131,12 +135,36 @@ const setVisualizer = ndx => {
131
135
setSelectOption ( visualTypeElem , ndx ) ;
132
136
} ;
133
137
138
+ try {
139
+ g_localSettings = JSON . parse ( localStorage . getItem ( 'localSettings' ) ) ;
140
+ } catch {
141
+ }
142
+
143
+ {
144
+ if ( ! g_localSettings || typeof g_localSettings !== 'object' ) {
145
+ g_localSettings = { } ;
146
+ }
147
+ const defaultSettings = {
148
+ volume : 100 ,
149
+ } ;
150
+ for ( const [ key , value ] of Object . entries ( defaultSettings ) ) {
151
+ if ( typeof g_localSettings [ key ] != typeof value ) {
152
+ g_localSettings [ key ] = value ;
153
+ }
154
+ }
155
+ }
156
+
157
+ function saveSettings ( ) {
158
+ localStorage . setItem ( 'localSettings' , JSON . stringify ( g_localSettings ) ) ;
159
+ }
160
+
134
161
async function main ( ) {
135
162
canvas = $ ( 'visualization' ) ;
136
163
controls = $ ( 'controls' ) ;
137
164
138
165
g_context = new AudioContext ( ) ;
139
166
g_context . resume ( ) ; // needed for safari
167
+ g_gainNode = new GainNode ( g_context ) ;
140
168
await ByteBeatNode . setup ( g_context ) ;
141
169
g_byteBeat = new ByteBeatNode ( g_context ) ;
142
170
@@ -204,6 +232,22 @@ async function main() {
204
232
return select ;
205
233
}
206
234
235
+ function addVerticalRange ( options , props ) {
236
+ const fn = props . onChange ;
237
+ const valueElem = el ( 'div' , { textContent : options . value ?? 0 } ) ;
238
+ return el ( 'div' , { className : 'vertical-range' , tabIndex : 0 } , [
239
+ valueElem ,
240
+ el ( 'div' , { className : 'vertical-range-holder' } , [
241
+ el ( 'input' , { ...options , type : 'range' , onInput : ( e ) => {
242
+ valueElem . textContent = e . target . value ;
243
+ if ( fn ) {
244
+ fn ( e ) ;
245
+ }
246
+ } , } ) ,
247
+ ] ) ,
248
+ ] )
249
+ }
250
+
207
251
beatTypeElem = addSelection ( s_beatTypes , 0 , {
208
252
onChange ( event ) {
209
253
g_byteBeat . setType ( event . target . selectedIndex ) ;
@@ -229,6 +273,15 @@ async function main() {
229
273
} ) ;
230
274
controls . appendChild ( sampleRateElem ) ;
231
275
276
+ const volumeElem = addVerticalRange ( { min : 1 , max : 100 , step : 1 , value : g_localSettings . volume } , {
277
+ onChange ( event ) {
278
+ g_gainNode . gain . value = event . target . value / 100 ;
279
+ g_localSettings . volume = parseInt ( event . target . value ) ;
280
+ saveSettings ( ) ;
281
+ } ,
282
+ } ) ;
283
+ controls . appendChild ( volumeElem ) ;
284
+
232
285
if ( g_slow ) {
233
286
g_visualizers = [
234
287
{ name : 'none' , visualizer : new NullVisualizer ( ) } ,
0 commit comments