1
+ window . onload = linkAudio ;
2
+ var mouseDownEvent ;
3
+ var vibranceMode = false ;
4
+ var strobeMode = true ;
5
+ var inverseMode = false ;
6
+ var colourShift = true ;
7
+ var increment = true ;
8
+ var pulseSpacing = 20 ;
9
+ var pulse = 1 ;
10
+ var pulseMode = false ;
11
+ var visualizerElement ;
12
+ var foregroundElement ;
13
+ var settingsFXElement ;
14
+ var audioTag ;
15
+ var sredHex = "05" ;
16
+ var sgrnHex = "10" ;
17
+ var sbluHex = "15" ;
18
+ var oredHex = "33" ;
19
+ var ogrnHex = "aa" ;
20
+ var obluHex = "ff" ;
21
+ var audioData ;
22
+ var audioDataBackup ;
23
+ var audioCtx = new ( window . AudioContext || window . webkitAudioContext ) ( ) ;
24
+ var source1 ;
25
+ var source2 ;
26
+ var gainNode ;
27
+ var analyser = audioCtx . createAnalyser ( ) ;
28
+ analyser . fftSize = 2048 ;
29
+ var bufferLength = analyser . frequencyBinCount ;
30
+ var dataArray = new Uint8Array ( bufferLength ) ;
31
+ var HEIGHT ;
32
+ var WIDTH ;
33
+ var barHeight = 2 ;
34
+ var barWidth = 5 ;
35
+ var barSpacing = 1 ;
36
+ var bleed = 10 ;
37
+ var fgColour = "33aaff" ;
38
+ var bgColour = "051015" ;
39
+ var barSize = 55 ;
40
+ var activeBufferLength = bufferLength / 0.666 ;
41
+ var radio = getUrlVars ( ) [ "src" ] ;
42
+ analyser . getByteTimeDomainData ( dataArray ) ;
43
+ var fps ;
44
+ var lastFrame = new Date ( ) ;
45
+ var lastFrameFrame = lastFrame ;
46
+ var title ;
47
+
48
+ function getUrlVars ( ) {
49
+ var vars = { } ;
50
+ var parts = window . location . href . replace ( / [ ? & ] + ( [ ^ = & ] + ) = ( [ ^ & ] * ) / gi, function ( m , key , value ) {
51
+ vars [ key ] = value ;
52
+ } ) ;
53
+ return vars ;
54
+ // From http://papermashup.com/read-url-get-variables-withjavascript/
55
+ }
56
+
57
+ function checkUrl ( ) {
58
+ if ( radio ) {
59
+ document . querySelector ( "source" ) . setAttribute ( "src" , radio ) ;
60
+ document . getElementById ( "Stream" ) . load ( ) ;
61
+ document . getElementById ( "Stream" ) . play ( ) ;
62
+ var split = radio . split ( ".com" ) [ 0 ] . split ( "." ) ;
63
+ radioName = split [ split . length - 1 ] ;
64
+ radioName = radioName [ 0 ] . toUpperCase ( ) + radioName . slice ( 1 ) ;
65
+ }
66
+ }
67
+
68
+ function init ( ) {
69
+ checkUrl ( ) ;
70
+ HEIGHT = window . innerHeight ;
71
+ WIDTH = window . innerWidth ;
72
+ canvas . height = HEIGHT ;
73
+ canvas . width = WIDTH ;
74
+ for ( var i = 0 ; i < WIDTH / 55 ; i ++ ) {
75
+ $ ( "#bars" ) . append ( "<div class='bar'></div>" ) ;
76
+ $ ( "#bars-blur" ) . append ( "<div class='bar'></div>" ) ;
77
+ }
78
+ visualizerElement = document . getElementById ( "visualizer" ) ;
79
+ foregroundElement = document . getElementById ( "foreground" ) ;
80
+ settingsFXElement = document . getElementById ( "settings-fx-wrapper" ) ;
81
+ visualizerElement . setAttribute ( "style" , "background:#" + bgColour ) ;
82
+ sredHex = parseInt ( bgColour [ 0 ] + bgColour [ 1 ] , 16 ) ;
83
+ sgrnHex = parseInt ( bgColour [ 2 ] + bgColour [ 3 ] , 16 ) ;
84
+ sbluHex = parseInt ( bgColour [ 4 ] + bgColour [ 5 ] , 16 ) ;
85
+ oredHex = parseInt ( fgColour [ 0 ] + fgColour [ 1 ] , 16 ) ;
86
+ ogrnHex = parseInt ( fgColour [ 2 ] + fgColour [ 3 ] , 16 ) ;
87
+ obluHex = parseInt ( fgColour [ 4 ] + fgColour [ 5 ] , 16 ) ;
88
+ setVol ( 0.5 ) ;
89
+ anim ( ) ;
90
+ }
91
+
92
+ function GetInfo ( ) {
93
+ var element = document . getElementById ( "Stream" ) ;
94
+ }
95
+
96
+ $ ( window ) . resize ( function ( ) {
97
+ HEIGHT = window . innerHeight ;
98
+ WIDTH = window . innerWidth ;
99
+ canvas . height = HEIGHT ;
100
+ canvas . width = WIDTH ;
101
+ } ) ;
102
+
103
+ function SettingsToggle ( ) {
104
+ if ( document . getElementById ( "settings" ) . style . left === "-230px" || ! document . getElementById ( "settings" ) . style . left ) {
105
+ document . getElementById ( "settings" ) . style . left = "0px" ;
106
+ document . getElementById ( "settings-toggle" ) . style . margin = "0px" ;
107
+ document . getElementById ( "settings-toggle" ) . innerHTML = "<" ;
108
+ } else {
109
+ document . getElementById ( "settings" ) . style . left = "-230px" ;
110
+ document . getElementById ( "settings-toggle" ) . style . margin = "0px -60px 0px 0px" ;
111
+ document . getElementById ( "settings-toggle" ) . innerHTML = ">" ;
112
+ }
113
+ }
114
+
115
+ function NewSource ( ) {
116
+ radio = document . getElementById ( "srInput" ) . value ;
117
+ document . querySelector ( "source" ) . setAttribute ( "src" , radio ) ;
118
+ document . getElementById ( "Stream" ) . load ( ) ;
119
+ document . getElementById ( "Stream" ) . play ( ) ;
120
+ window . history . pushState ( "Radio Visualizer" , "Canvas Web Audio API Music Visualizer" , window . location . href . split ( "?" ) [ 0 ] + "?src=" + radio ) ;
121
+ var split = radio . split ( ".com" ) [ 0 ] . split ( "." ) ;
122
+ radioName = split [ split . length - 1 ] ;
123
+ radioName = radioName [ 0 ] . toUpperCase ( ) + radioName . slice ( 1 ) ;
124
+ }
125
+
126
+ function NewBGColour ( ) {
127
+ var input = document . getElementById ( "bgInput" ) . value ;
128
+ input = input . replace ( "#" , "" ) ;
129
+ if ( input . length === 6 ) {
130
+ bgColour = input ;
131
+ $ ( "svg" ) . css ( { "fill" :"#" + bgColour , "stroke" :"#" + fgColour } ) ;
132
+ visualizerElement . setAttribute ( "style" , "background:#" + bgColour ) ;
133
+ }
134
+ else if ( parseInt ( input ) !== "NaN" && input . legnth < 4 ) {
135
+ bgColour = parseInt ( input , 16 ) . toString ( 16 ) ;
136
+ $ ( "svg" ) . css ( { "fill" :"#" + bgColour , "stroke" :"#" + fgColour } ) ;
137
+ visualizerElement . setAttribute ( "style" , "background:#" + bgColour ) ;
138
+ }
139
+ else {
140
+ alert ( "Please enter decimal or hex code" ) ;
141
+ }
142
+ oredHex = parseInt ( fgColour [ 0 ] + fgColour [ 1 ] , 16 ) ;
143
+ ogrnHex = parseInt ( fgColour [ 2 ] + fgColour [ 3 ] , 16 ) ;
144
+ obluHex = parseInt ( fgColour [ 4 ] + fgColour [ 5 ] , 16 ) ;
145
+ }
146
+
147
+ function NewFGColour ( ) {
148
+ var input = document . getElementById ( "fgInput" ) . value ;
149
+ input = input . replace ( "#" , "" ) ;
150
+ if ( input . length === 6 ) {
151
+ fgColour = input ;
152
+ if ( parseInt ( fgColour [ 0 ] ) < 1 && parseInt ( fgColour [ 2 ] ) < 1 && parseInt ( fgColour [ 4 ] ) < 1 ) {
153
+ document . body . style . color = "#ffffff" ;
154
+ $ ( 'input' ) . css ( 'color' , '#ffffff' ) ;
155
+ } else {
156
+ document . body . style . color = "#" + fgColour ;
157
+ $ ( 'input' ) . css ( 'color' , '#' + fgColour ) ;
158
+ $ ( "#current-volume" ) . css ( { "fill" :"#" + bgColour } ) ;
159
+ }
160
+ }
161
+ else if ( parseInt ( input ) !== "NaN" && input . legnth < 4 ) {
162
+ fgColour = parseInt ( input , 16 ) . toString ( 16 ) ;
163
+ document . body . style . color = "#" + fgColour ;
164
+ $ ( 'input' ) . css ( 'color' , '#' + fgColour ) ;
165
+ }
166
+ else {
167
+ alert ( "Please enter decimal or hex code" ) ;
168
+ }
169
+ sredHex = parseInt ( bgColour [ 0 ] + bgColour [ 1 ] , 16 ) ;
170
+ sgrnHex = parseInt ( bgColour [ 2 ] + bgColour [ 3 ] , 16 ) ;
171
+ sbluHex = parseInt ( bgColour [ 4 ] + bgColour [ 5 ] , 16 ) ;
172
+ }
173
+
174
+ function NewBleedQuality ( ) {
175
+ bleed = parseInt ( document . getElementById ( "bqInput" ) . value ) ;
176
+ }
177
+
178
+ function NewBarHeight ( ) {
179
+ barHeight = 2 - document . getElementById ( "bhInput" ) . value ;
180
+ }
181
+
182
+ function NewBarWidth ( ) {
183
+ barWidth = parseInt ( document . getElementById ( "bwInput" ) . value ) ;
184
+ }
185
+
186
+ function NewBarSpacing ( ) {
187
+ barSpacing = parseInt ( document . getElementById ( "bsInput" ) . value ) ;
188
+ }
189
+
190
+ function anim ( ) {
191
+ pulse = 1 ;
192
+ drawVisual = requestAnimationFrame ( anim ) ;
193
+ analyser . getByteFrequencyData ( dataArray ) ;
194
+ var mean = 0 ;
195
+ canvasCtx . fillStyle = "#3af" ;
196
+ canvasCtx . clearRect ( 0 , 0 , WIDTH , HEIGHT ) ;
197
+ for ( var i = 0 ; i < bufferLength * 0.666 ; i ++ ) {
198
+ var v = dataArray [ i ] / 128.0 ;
199
+ var h = v * HEIGHT / 2 ;
200
+ mean += h ;
201
+ var sred = sredHex ;
202
+ var sgrn = sgrnHex ;
203
+ var sblu = sbluHex ;
204
+ var ored = oredHex ;
205
+ var ogrn = ogrnHex ;
206
+ var oblu = obluHex ;
207
+ var tred = ored / 2 ;
208
+ var tgrn = ogrn / 2 ;
209
+ var tblu = oblu / 2 ;
210
+ var amp = 0 ;
211
+ var loud = Math . abs ( dataArray [ i ] ) ;
212
+ var cred = sred ;
213
+ var cgrn = sgrn ;
214
+ var cblu = sblu ;
215
+ if ( pulseMode === true ) {
216
+ opacity = ( 1 / pulseSpacing ) * pulse ;
217
+ } else {
218
+ opacity = 1 ;
219
+ }
220
+
221
+ if ( loud > amp ) {
222
+ amp = loud ;
223
+ }
224
+ if ( vibranceMode === true ) {
225
+ document . body . setAttribute ( "style" , "-webkit-filter:brightness(" + ( amp / 256 + 1 ) + ")" ) ;
226
+ } else {
227
+ document . body . removeAttribute ( "style" ) ;
228
+ }
229
+ var redinc = Math . floor ( ( tred - sred ) / bleed ) ;
230
+ var grninc = Math . floor ( ( tgrn - sgrn ) / bleed ) ;
231
+ var bluinc = Math . floor ( ( tblu - sblu ) / bleed ) ;
232
+
233
+ for ( var o = 0 ; o < bleed ; o ++ ) {
234
+ if ( o < bleed - 1 ) {
235
+ //--TODO-- Check for outerbars mode
236
+ cred += redinc ;
237
+ cgrn += grninc ;
238
+ cblu += bluinc ;
239
+
240
+ red = cred ;
241
+ green = cgrn ;
242
+ blue = cblu ;
243
+ canvasCtx . fillStyle = "rgba(" + red + "," + green + "," + blue + "," + opacity + ")" ;
244
+ canvasCtx . fillRect ( i * ( barWidth + barSpacing ) , HEIGHT / 2 - ( ( 2 - ( o / bleed ) ) * h / ( 2 * barHeight ) ) , barWidth , ( ( ( 2 - ( o / bleed ) ) * h ) / barHeight ) ) ;
245
+ } else {
246
+ red = ored ;
247
+ green = ogrn ;
248
+ blue = oblu ;
249
+ canvasCtx . fillStyle = "rgba(" + red + "," + green + "," + blue + "," + opacity + ")" ;
250
+ canvasCtx . fillRect ( i * ( barWidth + barSpacing ) , HEIGHT / 2 - h / ( barHeight * 2 ) , barWidth , h / barHeight ) ;
251
+ }
252
+ }
253
+ if ( increment === true ) {
254
+ pulse ++ ;
255
+ }
256
+ else {
257
+ pulse -- ;
258
+ }
259
+ if ( pulse > pulseSpacing - 1 ) {
260
+ increment = false ;
261
+ } else if ( pulse < 1 ) {
262
+ increment = true ;
263
+ }
264
+ mean = 0 ;
265
+ }
266
+ var total = Math . floor ( audioTag . currentTime ) ;
267
+ var seconds = Math . floor ( total % 60 ) . toString ( ) ;
268
+ var minutes = Math . floor ( total / 60 % 60 ) . toString ( ) ;
269
+ var hours = Math . floor ( total / 3600 ) . toString ( ) ;
270
+ var ouput ;
271
+ if ( hours . length === 1 ) {
272
+ hours = "0" + hours ;
273
+ }
274
+ if ( minutes . length === 1 ) {
275
+ minutes = "0" + minutes ;
276
+ }
277
+ if ( seconds . length === 1 ) {
278
+ seconds = "0" + seconds ;
279
+ }
280
+ canvasCtx . strokeStyle = "#" + fgColour ;
281
+ canvasCtx . lineWidth = 3 ;
282
+ canvasCtx . font = "30px Play" ;
283
+ canvasCtx . strokeText ( hours + ":" + minutes + ":" + seconds , 10 , HEIGHT / 2 + 30 ) ;
284
+ canvasCtx . font = "60px Play" ;
285
+ canvasCtx . strokeText ( radioName , 10 , HEIGHT / 2 ) ;
286
+ canvasCtx . fillStyle = "#" + bgColour ;
287
+ canvasCtx . font = "30px Play" ;
288
+ canvasCtx . fillText ( hours + ":" + minutes + ":" + seconds , 10 , HEIGHT / 2 + 30 ) ;
289
+ canvasCtx . font = "60px Play" ;
290
+ canvasCtx . fillText ( radioName , 10 , HEIGHT / 2 ) ;
291
+
292
+ var now = new Date ( ) ;
293
+ if ( now - lastFrameFrame > 100 ) {
294
+ fps = Math . floor ( 1000 / ( now - lastFrame ) ) ;
295
+ lastFrameFrame = now ;
296
+ }
297
+ canvasCtx . font = "30px Play" ;
298
+ canvasCtx . strokeStyle = "#" + fgColour ;
299
+ canvasCtx . strokeText ( title , WIDTH / 2 - 100 , HEIGHT / 2 + 10 ) ;
300
+ canvasCtx . fillText ( title , WIDTH / 2 - 100 , HEIGHT / 2 + 10 ) ;
301
+ lastFrame = now ;
302
+ }
303
+
304
+ function linkAudio ( ) {
305
+ gainNode = audioCtx . createGain ( ) ;
306
+ analyser . connect ( gainNode ) ;
307
+ gainNode . connect ( audioCtx . destination ) ;
308
+ canvas = document . getElementById ( "visualizer" ) ;
309
+ audioTag = document . querySelector ( 'audio' ) ;
310
+ canvasCtx = canvas . getContext ( "2d" ) ;
311
+ source1 = audioCtx . createMediaElementSource ( audioTag ) ;
312
+ source1 . connect ( analyser ) ;
313
+ init ( ) ;
314
+ }
315
+
316
+ function start ( ) {
317
+ document . getElementById ( "Stream" ) . play ( ) ;
318
+ }
319
+
320
+ function pause ( ) {
321
+ document . getElementById ( "Stream" ) . pause ( ) ;
322
+ }
323
+
324
+ $ ( '#volume-bar' ) . mousedown ( function ( ) {
325
+ setVol ( $ ( '#volume-bar' ) . val ( ) ) ;
326
+ mouseDownEvent = setInterval ( function ( ) {
327
+ setVol ( $ ( '#volume-bar' ) . val ( ) ) ;
328
+ } , 100 ) ;
329
+ } ) ;
330
+ $ ( '#volume-bar' ) . mouseup ( function ( ) {
331
+ clearInterval ( mouseDownEvent ) ;
332
+ } ) ;
333
+ $ ( '#volume-bar' ) . mouseout ( function ( ) {
334
+ clearInterval ( mouseDownEvent ) ;
335
+ } ) ;
336
+
337
+ function setVol ( value ) {
338
+ gainNode . gain . value = value ;
339
+ document . getElementById ( "current-volume" ) . style . width = ( 119 * value ) + "px" ;
340
+ }
341
+
342
+ $ ( ".filter-toggle" ) . click ( function ( ) {
343
+ firstChild = this . children [ 0 ] ;
344
+ secondChild = this . children [ 1 ] ;
345
+
346
+ if ( firstChild . hasAttribute ( "style" ) ) {
347
+ firstChild . removeAttribute ( "style" ) ;
348
+ secondChild . setAttribute ( "style" , "opacity:0.2;" ) ;
349
+ } else {
350
+ firstChild . setAttribute ( "style" , "opacity:0.2;" ) ;
351
+ secondChild . removeAttribute ( "style" ) ;
352
+ }
353
+ } ) ;
354
+
355
+ function toggleFX ( string ) {
356
+ if ( string === "vibrance" ) {
357
+ vibranceMode = ! vibranceMode ;
358
+ } else if ( string === "strobe" ) {
359
+ strobeMode = ! strobeMode ;
360
+ } else if ( string === "inverse" ) {
361
+ inverseMode = ! inverseMode ;
362
+ } else if ( string === "colourShift" ) {
363
+ if ( ! colourShift ) {
364
+ colourShift = setInterval ( function ( ) { $ ( "#body-fx-wrapper" ) . css ( "-webkit-filter" , "hue-rotate(" + ( Math . random ( ) * 360 ) + "deg)" ) ; } , 1000 ) ;
365
+ } else {
366
+ clearInterval ( colourShift ) ;
367
+ colourShift = false ;
368
+ }
369
+ } else if ( string === "pulse" ) {
370
+ pulseMode = ! pulseMode ;
371
+ }
372
+ }
373
+
374
+ ( function worker ( ) {
375
+ $ . ajax ( {
376
+ url : 'fetcher.php?host=' + host ,
377
+ success : function ( data ) {
378
+ title = data ;
379
+ document . title = data ;
380
+ } ,
381
+ complete : function ( ) {
382
+ // Schedule the next request when the current one's complete
383
+ setTimeout ( worker , 3000 ) ;
384
+ }
385
+ } ) ;
386
+ } ) ( ) ;
0 commit comments