├── README
├── audio_scripts
├── anim.pde
├── beatdetektor.js
├── dsp.js
├── main.js
└── processing.js
├── demo.html
├── demos.css
├── fonts
├── BebasNeue.otf
├── MEgalopolisExtra.woff
├── MarketingScript.ttf
└── ubuntu.ttf
├── imgs
├── bgr.jpg
├── close.png
├── controls.jpg
├── dashed.png
├── link.png
├── lion.svg
├── overlay.png
├── phial.svg
├── progress.png
├── texture.png
├── throbber.gif
├── tiger.svg
├── tv-border.jpg
└── whiteButton.png
├── logos
├── android.png
├── apple.png
├── linux.png
├── maemo.png
├── meego.png
├── w3c.png
├── webm.png
├── windows.png
└── xiph.png
├── media
├── enfants.webm
└── track.ogg
├── screenshot.jpg
├── scripts
├── audioplayer.js
├── canvas2d.js
├── classList.js
├── dnd.js
├── geolocation.js
├── jquery.jplayer.min.js
├── jquery.rotate.js
├── main.js
└── orientation.js
├── style.css
└── webgl_assets
├── Teapot.json
├── glUtils.js
├── gldemo.js
├── sylvester.js
└── texture.jpg
/README:
--------------------------------------------------------------------------------
1 | HTML5 Dashboard!
2 |
--------------------------------------------------------------------------------
/audio_scripts/anim.pde:
--------------------------------------------------------------------------------
1 | int x_step;
2 | int x_width;
3 | int bar_height;
4 | int width = 128;
5 | int height = 128;
6 |
7 | void setup() {
8 | size(128, 128);
9 | noLoop();
10 | }
11 |
12 | void draw() {
13 | background(0, 0, 0, 0);
14 | noStroke();
15 | fill(225, 230, 233, 255);
16 |
17 | if ( bd.beat_counter % 4 == 0 ) {
18 | rect(2, 2, 60, 60);
19 | } else if ( bd.beat_counter % 4 == 1 ) {
20 | rect(2, 66, 60, 60);
21 | } else if ( bd.beat_counter % 4 == 2 ) {
22 | rect(66, 66, 60, 60);
23 | } else if ( bd.beat_counter % 4 == 3 ) {
24 | rect(66, 2, 60, 60);
25 | }
26 |
27 | strokeWeight(0.0);
28 |
29 | if (vu.vu_levels.length) {
30 | int x_step = (width/(bd.config.BD_DETECTION_RANGES/4));
31 | int x_width = (width/(bd.config.BD_DETECTION_RANGES/4))-2;
32 |
33 | fill(108, 207, 228, 255);
34 | for (int i = 0; i < bd.config.BD_DETECTION_RANGES/4; i++) {
35 | int v_i = i;
36 |
37 | int sz;
38 | sz = 64*vu.vu_levels[v_i];
39 | if (sz>64) sz = 64;
40 |
41 | rect(i*x_step,128-sz,2,sz);
42 | }
43 | }
44 |
45 | strokeWeight(3);
46 | stroke(108, 207, 228, 255);
47 |
48 | for ( int i = 0; i < 128; i++) {
49 | float mi = Math.abs(signal[4*i]);
50 | line(i, 32 - signal[4*i] * 32, i + 1, 32 - signal[4*(i+1)] * 32)
51 | }
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/audio_scripts/beatdetektor.js:
--------------------------------------------------------------------------------
1 | /*
2 | * BeatDetektor.js
3 | *
4 | * BeatDetektor - CubicFX Visualizer Beat Detection & Analysis Algorithm
5 | * Javascript port by Charles J. Cliffe and Corban Brook
6 | *
7 | * Created by Charles J. Cliffe on 09-11-30.
8 | * Copyright 2009 Charles J. Cliffe. All rights reserved.
9 | *
10 | * BeatDetektor is free software: you can redistribute it and/or modify
11 | * it under the terms of the GNU Lesser General Public License as published by
12 | * the Free Software Foundation, either version 3 of the License, or
13 | * (at your option) any later version.
14 | *
15 | * Please note that only the Javascript version of BeatDetektor is licensed
16 | * under the terms of LGPL version 3; ports of BeatDetektor or derivatives
17 | * in other languages are licensed under the terms of GPL version 3.
18 | *
19 | * BeatDetektor is distributed in the hope that it will be useful,
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 | * GNU Lesser General Public License for more details.
23 | *
24 | * You should have received a copy of the GNU Lesser General Public License
25 | * along with this program. If not, see .
26 | *
27 | * Please contact cj@cubicproductions.com if you seek alternate
28 | * licensing terms for your project.
29 | *
30 | */
31 |
32 |
33 | /*
34 | BeatDetektor class
35 |
36 |
37 | Theory:
38 |
39 | Trigger detection is performed using a trail of moving averages,
40 |
41 | The FFT input is broken up into 128 ranges and averaged, each range has two moving
42 | averages that tail each other at a rate of (1.0 / BD_DETECTION_RATE) seconds.
43 |
44 | Each time the moving average for a range exceeds it's own tailing average by:
45 |
46 | (moving_average[range] * BD_DETECTION_FACTOR >= moving_average[range])
47 |
48 | if this is true there's a rising edge and a detection is flagged for that range.
49 | Next a trigger gap test is performed between rising edges and timestamp recorded.
50 |
51 | If the gap is larger than our BPM window (in seconds) then we can discard it and
52 | reset the timestamp for a new detection -- but only after checking to see if it's a
53 | reasonable match for 2* the current detection in case it's only triggered every
54 | other beat. Gaps that are lower than the BPM window are ignored and the last
55 | timestamp will not be reset.
56 |
57 | Gaps that are within a reasonable window are run through a quality stage to determine
58 | how 'close' they are to that channel's current prediction and are incremented or
59 | decremented by a weighted value depending on accuracy. Repeated hits of low accuracy
60 | will still move a value towards erroneous detection but it's quality will be lowered
61 | and will not be eligible for the gap time quality draft.
62 |
63 | Once quality has been assigned ranges are reviewed for good match candidates and if
64 | BD_MINIMUM_CONTRIBUTIONS or more ranges achieve a decent ratio (with a factor of
65 | BD_QUALITY_TOLERANCE) of contribution to the overall quality we take them into the
66 | contest round. Note that the contest round won't run on a given process() call if
67 | the total quality achieved does not meet or exceed BD_QUALITY_TOLERANCE.
68 |
69 | Each time through if a select draft of BPM ranges has achieved a reasonable quality
70 | above others it's awarded a value in the BPM contest. The BPM contest is a hash
71 | array indexed by an integer BPM value, each draft winner is awarded BD_QUALITY_REWARD.
72 |
73 | Finally the BPM contest is examined to determine a leader and all contest entries
74 | are normalized to a total value of BD_FINISH_LINE, whichever range is closest to
75 | BD_FINISH_LINE at any given point is considered to be the best guess however waiting
76 | until a minimum contest winning value of about 20.0-25.0 will provide more accurate
77 | results. Note that the 20-25 rule may vary with lower and higher input ranges.
78 | A winning value that exceeds 40 or hovers around 60 (the finish line) is pretty much
79 | a guaranteed match.
80 |
81 |
82 | Configuration Kernel Notes:
83 |
84 | The majority of the ratios and values have been reverse-engineered from my own
85 | observation and visualization of information from various aspects of the detection
86 | triggers; so not all parameters have a perfect definition nor perhaps the best value yet.
87 | However despite this it performs very well; I had expected several more layers
88 | before a reasonable detection would be achieved. Comments for these parameters will be
89 | updated as analysis of their direct effect is explored.
90 |
91 |
92 | Input Restrictions:
93 |
94 | bpm_maximum must be within the range of (bpm_minimum*2)-1
95 | i.e. minimum of 50 must have a maximum of 99 because 50*2 = 100
96 |
97 |
98 | Changelog:
99 |
100 | 01/17/2010 - Charles J. Cliffe
101 | - Tested and tweaked default kernel values for tighter detection
102 | - Added BeatDetektor.config_48_95, BeatDetektor.config_90_179 and BeatDetektor.config_150_280 for more refined detection ranges
103 | - Updated unit test to include new range config example
104 |
105 | 02/21/2010 - Charles J. Cliffe
106 | - Fixed numerous bugs and divide by 0 on 1% match causing poor accuracy
107 | - Re-worked the quality calulations, accuracy improved 8-10x
108 | - Primary value is now a fractional reading (*10, just divide by 10), added win_bpm_int_lo for integral readings
109 | - Added feedback loop for current_bpm to help back-up low quality channels
110 | - Unified range configs, now single default should be fine
111 | - Extended quality reward 'funnel'
112 |
113 | */
114 | BeatDetektor = function(bpm_minimum, bpm_maximum, alt_config)
115 | {
116 | if (typeof(bpm_minimum)=='undefined') bpm_minimum = 85.0;
117 | if (typeof(bpm_maximum)=='undefined') bpm_maximum = 169.0
118 |
119 | this.config = (typeof(alt_config)!='undefined')?alt_config:BeatDetektor.config;
120 |
121 | this.BPM_MIN = bpm_minimum;
122 | this.BPM_MAX = bpm_maximum;
123 |
124 | this.beat_counter = 0;
125 | this.half_counter = 0;
126 | this.quarter_counter = 0;
127 |
128 | // current average (this sample) for range n
129 | this.a_freq_range = new Array(this.config.BD_DETECTION_RANGES);
130 | // moving average of frequency range n
131 | this.ma_freq_range = new Array(this.config.BD_DETECTION_RANGES);
132 | // moving average of moving average of frequency range n
133 | this.maa_freq_range = new Array(this.config.BD_DETECTION_RANGES);
134 | // timestamp of last detection for frequecy range n
135 | this.last_detection = new Array(this.config.BD_DETECTION_RANGES);
136 |
137 | // moving average of gap lengths
138 | this.ma_bpm_range = new Array(this.config.BD_DETECTION_RANGES);
139 | // moving average of moving average of gap lengths
140 | this.maa_bpm_range = new Array(this.config.BD_DETECTION_RANGES);
141 |
142 | // range n quality attribute, good match = quality+, bad match = quality-, min = 0
143 | this.detection_quality = new Array(this.config.BD_DETECTION_RANGES);
144 |
145 | // current trigger state for range n
146 | this.detection = new Array(this.config.BD_DETECTION_RANGES);
147 |
148 | this.reset();
149 |
150 | if (typeof(console)!='undefined')
151 | {
152 | console.log("BeatDetektor("+this.BPM_MIN+","+this.BPM_MAX+") created.")
153 | }
154 | }
155 |
156 | BeatDetektor.prototype.reset = function()
157 | {
158 | // var bpm_avg = 60.0/((this.BPM_MIN+this.BPM_MAX)/2.0);
159 |
160 | for (var i = 0; i < this.config.BD_DETECTION_RANGES; i++)
161 | {
162 | this.a_freq_range[i] = 0.0;
163 | this.ma_freq_range[i] = 0.0;
164 | this.maa_freq_range[i] = 0.0;
165 | this.last_detection[i] = 0.0;
166 |
167 | this.ma_bpm_range[i] =
168 | this.maa_bpm_range[i] = 60.0/this.BPM_MIN + ((60.0/this.BPM_MAX-60.0/this.BPM_MIN) * (i/this.config.BD_DETECTION_RANGES));
169 |
170 | this.detection_quality[i] = 0.0;
171 | this.detection[i] = false;
172 | }
173 |
174 | this.ma_quality_avg = 0;
175 | this.ma_quality_total = 0;
176 |
177 | this.bpm_contest = new Array();
178 | this.bpm_contest_lo = new Array();
179 |
180 | this.quality_total = 0.0;
181 | this.quality_avg = 0.0;
182 |
183 | this.current_bpm = 0.0;
184 | this.current_bpm_lo = 0.0;
185 |
186 | this.winning_bpm = 0.0;
187 | this.win_val = 0.0;
188 | this.winning_bpm_lo = 0.0;
189 | this.win_val_lo = 0.0;
190 |
191 | this.win_bpm_int = 0;
192 | this.win_bpm_int_lo = 0;
193 |
194 | this.bpm_predict = 0;
195 |
196 | this.is_erratic = false;
197 | this.bpm_offset = 0.0;
198 | this.last_timer = 0.0;
199 | this.last_update = 0.0;
200 |
201 | this.bpm_timer = 0.0;
202 | this.beat_counter = 0;
203 | this.half_counter = 0;
204 | this.quarter_counter = 0;
205 | }
206 |
207 |
208 | BeatDetektor.config_default = {
209 | BD_DETECTION_RANGES : 128, // How many ranges to quantize the FFT into
210 | BD_DETECTION_RATE : 12.0, // Rate in 1.0 / BD_DETECTION_RATE seconds
211 | BD_DETECTION_FACTOR : 0.915, // Trigger ratio
212 | BD_QUALITY_DECAY : 0.6, // range and contest decay
213 | BD_QUALITY_TOLERANCE : 0.96,// Use the top x % of contest results
214 | BD_QUALITY_REWARD : 10.0, // Award weight
215 | BD_QUALITY_STEP : 0.1, // Award step (roaming speed)
216 | BD_MINIMUM_CONTRIBUTIONS : 6, // At least x ranges must agree to process a result
217 | BD_FINISH_LINE : 60.0, // Contest values wil be normalized to this finish line
218 | // this is the 'funnel' that pulls ranges in / out of alignment based on trigger detection
219 | BD_REWARD_TOLERANCES : [ 0.001, 0.005, 0.01, 0.02, 0.04, 0.08, 0.10, 0.15, 0.30 ], // .1%, .5%, 1%, 2%, 4%, 8%, 10%, 15%
220 | BD_REWARD_MULTIPLIERS : [ 20.0, 10.0, 8.0, 1.0, 1.0/2.0, 1.0/4.0, 1.0/8.0, 1/16.0, 1/32.0 ]
221 | };
222 |
223 |
224 | // Default configuration kernel
225 | BeatDetektor.config = BeatDetektor.config_default;
226 |
227 |
228 | BeatDetektor.prototype.process = function(timer_seconds, fft_data)
229 | {
230 | if (!this.last_timer) { this.last_timer = timer_seconds; return; } // ignore 0 start time
231 | if (this.last_timer > timer_seconds) { this.reset(); return; }
232 |
233 | var timestamp = timer_seconds;
234 |
235 | this.last_update = timer_seconds - this.last_timer;
236 | this.last_timer = timer_seconds;
237 |
238 | if (this.last_update > 1.0) { this.reset(); return; }
239 |
240 | var i,x;
241 | var v;
242 |
243 | var bpm_floor = 60.0/this.BPM_MAX;
244 | var bpm_ceil = 60.0/this.BPM_MIN;
245 |
246 | var range_step = (fft_data.length / this.config.BD_DETECTION_RANGES);
247 | var range = 0;
248 |
249 |
250 | for (x=0; x= this.maa_freq_range[range]);
273 |
274 | // compute bpm clamps for comparison to gap lengths
275 |
276 | // clamp detection averages to input ranges
277 | if (this.ma_bpm_range[range] > bpm_ceil) this.ma_bpm_range[range] = bpm_ceil;
278 | if (this.ma_bpm_range[range] < bpm_floor) this.ma_bpm_range[range] = bpm_floor;
279 | if (this.maa_bpm_range[range] > bpm_ceil) this.maa_bpm_range[range] = bpm_ceil;
280 | if (this.maa_bpm_range[range] < bpm_floor) this.maa_bpm_range[range] = bpm_floor;
281 |
282 | var rewarded = false;
283 |
284 | // new detection since last, test it's quality
285 | if (!this.detection[range] && det)
286 | {
287 | // calculate length of gap (since start of last trigger)
288 | var trigger_gap = timestamp-this.last_detection[range];
289 |
290 | // trigger falls within acceptable range,
291 | if (trigger_gap < bpm_ceil && trigger_gap > (bpm_floor))
292 | {
293 | // compute gap and award quality
294 |
295 | // use our tolerances as a funnel to edge detection towards the most likely value
296 | for (i = 0; i < this.config.BD_REWARD_TOLERANCES.length; i++)
297 | {
298 | if (Math.abs(this.ma_bpm_range[range]-trigger_gap) < this.ma_bpm_range[range]*this.config.BD_REWARD_TOLERANCES[i])
299 | {
300 | this.detection_quality[range] += this.config.BD_QUALITY_REWARD * this.config.BD_REWARD_MULTIPLIERS[i];
301 | rewarded = true;
302 | }
303 | }
304 |
305 | if (rewarded)
306 | {
307 | this.last_detection[range] = timestamp;
308 | }
309 | }
310 | else if (trigger_gap >= bpm_ceil) // low quality, gap exceeds maximum time
311 | {
312 | // start a new gap test, next gap is guaranteed to be longer
313 |
314 | // test for 1/2 beat
315 | trigger_gap /= 2.0;
316 |
317 | if (trigger_gap < bpm_ceil && trigger_gap > (bpm_floor)) for (i = 0; i < this.config.BD_REWARD_TOLERANCES.length; i++)
318 | {
319 | if (Math.abs(this.ma_bpm_range[range]-trigger_gap) < this.ma_bpm_range[range]*this.config.BD_REWARD_TOLERANCES[i])
320 | {
321 | this.detection_quality[range] += this.config.BD_QUALITY_REWARD * this.config.BD_REWARD_MULTIPLIERS[i];
322 | rewarded = true;
323 | }
324 | }
325 |
326 |
327 | // decrement quality if no 1/2 beat reward
328 | if (!rewarded)
329 | {
330 | trigger_gap *= 2.0;
331 | }
332 | this.last_detection[range] = timestamp;
333 | }
334 |
335 | if (rewarded)
336 | {
337 | var qmp = (this.detection_quality[range]/this.quality_avg)*this.config.BD_QUALITY_STEP;
338 | if (qmp > 1.0)
339 | {
340 | qmp = 1.0;
341 | }
342 |
343 | this.ma_bpm_range[range] -= (this.ma_bpm_range[range]-trigger_gap) * qmp;
344 | this.maa_bpm_range[range] -= (this.maa_bpm_range[range]-this.ma_bpm_range[range]) * qmp;
345 | }
346 | else if (trigger_gap >= bpm_floor && trigger_gap <= bpm_ceil)
347 | {
348 | if (this.detection_quality[range] < this.quality_avg*this.config.BD_QUALITY_TOLERANCE && this.current_bpm)
349 | {
350 | this.ma_bpm_range[range] -= (this.ma_bpm_range[range]-trigger_gap) * this.config.BD_QUALITY_STEP;
351 | this.maa_bpm_range[range] -= (this.maa_bpm_range[range]-this.ma_bpm_range[range]) * this.config.BD_QUALITY_STEP;
352 | }
353 | this.detection_quality[range] -= this.config.BD_QUALITY_STEP;
354 | }
355 | else if (trigger_gap >= bpm_ceil)
356 | {
357 | if ((this.detection_quality[range] < this.quality_avg*this.config.BD_QUALITY_TOLERANCE) && this.current_bpm)
358 | {
359 | this.ma_bpm_range[range] -= (this.ma_bpm_range[range]-this.current_bpm) * 0.5;
360 | this.maa_bpm_range[range] -= (this.maa_bpm_range[range]-this.ma_bpm_range[range]) * 0.5 ;
361 | }
362 | this.detection_quality[range]-= this.config.BD_QUALITY_STEP;
363 | }
364 |
365 | }
366 |
367 | if ((!rewarded && timestamp-this.last_detection[range] > bpm_ceil) || (det && Math.abs(this.ma_bpm_range[range]-this.current_bpm) > this.bpm_offset))
368 | this.detection_quality[range] -= this.detection_quality[range]*this.config.BD_QUALITY_STEP*this.config.BD_QUALITY_DECAY*this.last_update;
369 |
370 | // quality bottomed out, set to 0
371 | if (this.detection_quality[range] < 0.001) this.detection_quality[range]=0.001;
372 |
373 | this.detection[range] = det;
374 |
375 | range++;
376 | }
377 |
378 | // total contribution weight
379 | this.quality_total = 0;
380 |
381 | // total of bpm values
382 | var bpm_total = 0;
383 | // number of bpm ranges that contributed to this test
384 | var bpm_contributions = 0;
385 |
386 |
387 | // accumulate quality weight total
388 | for (var x=0; x= this.ma_quality_avg)
423 | {
424 | if (this.ma_bpm_range[x] < bpm_ceil && this.ma_bpm_range[x] > bpm_floor)
425 | {
426 | bpm_total += this.maa_bpm_range[x];
427 |
428 | var draft_float = Math.round((60.0/this.maa_bpm_range[x])*1000.0);
429 |
430 | draft_float = (Math.abs(Math.ceil(draft_float)-(60.0/this.current_bpm)*1000.0)<(Math.abs(Math.floor(draft_float)-(60.0/this.current_bpm)*1000.0)))?Math.ceil(draft_float/10.0):Math.floor(draft_float/10.0);
431 | var draft_int = parseInt(draft_float/10.0);
432 | // if (draft_int) console.log(draft_int);
433 | if (typeof(draft[draft_int]=='undefined')) draft[draft_int] = 0;
434 |
435 | draft[draft_int]+=this.detection_quality[x]/this.quality_avg;
436 | bpm_contributions++;
437 | if (offset_test_bpm == 0.0) offset_test_bpm = this.maa_bpm_range[x];
438 | else
439 | {
440 | avg_bpm_offset += Math.abs(offset_test_bpm-this.maa_bpm_range[x]);
441 | }
442 |
443 |
444 | }
445 | }
446 | }
447 |
448 | // if we have one or more contributions that pass criteria then attempt to display a guess
449 | var has_prediction = (bpm_contributions>=this.config.BD_MINIMUM_CONTRIBUTIONS)?true:false;
450 |
451 | var draft_winner=0;
452 | var win_val = 0;
453 |
454 | if (has_prediction)
455 | {
456 | for (var draft_i in draft)
457 | {
458 | if (draft[draft_i] > win_val)
459 | {
460 | win_val = draft[draft_i];
461 | draft_winner = draft_i;
462 | }
463 | }
464 |
465 | this.bpm_predict = 60.0/(draft_winner/10.0);
466 |
467 | avg_bpm_offset /= bpm_contributions;
468 | this.bpm_offset = avg_bpm_offset;
469 |
470 | if (!this.current_bpm)
471 | {
472 | this.current_bpm = this.bpm_predict;
473 | }
474 | }
475 |
476 | if (this.current_bpm && this.bpm_predict) this.current_bpm -= (this.current_bpm-this.bpm_predict)*this.last_update;
477 |
478 | // hold a contest for bpm to find the current mode
479 | var contest_max=0;
480 |
481 | for (var contest_i in this.bpm_contest)
482 | {
483 | if (contest_max < this.bpm_contest[contest_i]) contest_max = this.bpm_contest[contest_i];
484 | if (this.bpm_contest[contest_i] > this.config.BD_FINISH_LINE/2.0)
485 | {
486 | var draft_int_lo = parseInt(Math.round((contest_i)/10.0));
487 | if (this.bpm_contest_lo[draft_int_lo] != this.bpm_contest_lo[draft_int_lo]) this.bpm_contest_lo[draft_int_lo] = 0;
488 | this.bpm_contest_lo[draft_int_lo]+= (this.bpm_contest[contest_i]/6.0)*this.last_update;
489 | }
490 | }
491 |
492 | // normalize to a finish line
493 | if (contest_max > this.config.BD_FINISH_LINE)
494 | {
495 | for (var contest_i in this.bpm_contest)
496 | {
497 | this.bpm_contest[contest_i]=(this.bpm_contest[contest_i]/contest_max)*this.config.BD_FINISH_LINE;
498 | }
499 | }
500 |
501 | contest_max = 0;
502 | for (var contest_i in this.bpm_contest_lo)
503 | {
504 | if (contest_max < this.bpm_contest_lo[contest_i]) contest_max = this.bpm_contest_lo[contest_i];
505 | }
506 |
507 | // normalize to a finish line
508 | if (contest_max > this.config.BD_FINISH_LINE)
509 | {
510 | for (var contest_i in this.bpm_contest_lo)
511 | {
512 | this.bpm_contest_lo[contest_i]=(this.bpm_contest_lo[contest_i]/contest_max)*this.config.BD_FINISH_LINE;
513 | }
514 | }
515 |
516 |
517 | // decay contest values from last loop
518 | for (contest_i in this.bpm_contest)
519 | {
520 | this.bpm_contest[contest_i]-=this.bpm_contest[contest_i]*(this.last_update/this.config.BD_DETECTION_RATE);
521 | }
522 |
523 | // decay contest values from last loop
524 | for (contest_i in this.bpm_contest_lo)
525 | {
526 | this.bpm_contest_lo[contest_i]-=this.bpm_contest_lo[contest_i]*(this.last_update/this.config.BD_DETECTION_RATE);
527 | }
528 |
529 | this.bpm_timer+=this.last_update;
530 |
531 | var winner = 0;
532 | var winner_lo = 0;
533 |
534 | // attempt to display the beat at the beat interval ;)
535 | if (this.bpm_timer > this.winning_bpm/4.0 && this.current_bpm)
536 | {
537 | this.win_val = 0;
538 | this.win_val_lo = 0;
539 |
540 | if (this.winning_bpm) while (this.bpm_timer > this.winning_bpm/4.0) this.bpm_timer -= this.winning_bpm/4.0;
541 |
542 | // increment beat counter
543 |
544 | this.quarter_counter++;
545 | this.half_counter= parseInt(this.quarter_counter/2);
546 | this.beat_counter = parseInt(this.quarter_counter/4);
547 |
548 | // award the winner of this iteration
549 | var idx = parseInt(Math.round((60.0/this.current_bpm)*10.0));
550 | if (typeof(this.bpm_contest[idx])=='undefined') this.bpm_contest[idx] = 0;
551 | this.bpm_contest[idx]+=this.config.BD_QUALITY_REWARD;
552 |
553 |
554 | // find the overall winner so far
555 | for (var contest_i in this.bpm_contest)
556 | {
557 | if (this.win_val < this.bpm_contest[contest_i])
558 | {
559 | winner = contest_i;
560 | this.win_val = this.bpm_contest[contest_i];
561 | }
562 | }
563 |
564 | if (winner)
565 | {
566 | this.win_bpm_int = parseInt(winner);
567 | this.winning_bpm = (60.0/(winner/10.0));
568 | }
569 |
570 | // find the overall winner so far
571 | for (var contest_i in this.bpm_contest_lo)
572 | {
573 | if (this.win_val_lo < this.bpm_contest_lo[contest_i])
574 | {
575 | winner_lo = contest_i;
576 | this.win_val_lo = this.bpm_contest_lo[contest_i];
577 | }
578 | }
579 |
580 | if (winner_lo)
581 | {
582 | this.win_bpm_int_lo = parseInt(winner_lo);
583 | this.winning_bpm_lo = 60.0/winner_lo;
584 | }
585 |
586 |
587 | if (typeof(console)!='undefined' && (this.beat_counter % 4) == 0) console.log("BeatDetektor("+this.BPM_MIN+","+this.BPM_MAX+"): [ Current Estimate: "+winner+" BPM ] [ Time: "+(parseInt(timer_seconds*1000.0)/1000.0)+"s, Quality: "+(parseInt(this.quality_total*1000.0)/1000.0)+", Rank: "+(parseInt(this.win_val*1000.0)/1000.0)+", Jitter: "+(parseInt(this.bpm_offset*1000000.0)/1000000.0)+" ]");
588 | }
589 |
590 | }
591 |
592 | // Sample Modules
593 | BeatDetektor.modules = new Object();
594 | BeatDetektor.modules.vis = new Object();
595 |
596 | // simple bass kick visualizer assistant module
597 | BeatDetektor.modules.vis.BassKick = function()
598 | {
599 | this.is_kick = false;
600 | }
601 |
602 | BeatDetektor.modules.vis.BassKick.prototype.process = function(det)
603 | {
604 | this.is_kick = ((det.detection[0] && det.detection[1]) || (det.ma_freq_range[0]/det.maa_freq_range[0])>1.4);
605 | }
606 |
607 | BeatDetektor.modules.vis.BassKick.prototype.isKick = function()
608 | {
609 | return this.is_kick;
610 | }
611 |
612 |
613 | // simple vu spectrum visualizer assistant module
614 | BeatDetektor.modules.vis.VU = function()
615 | {
616 | this.vu_levels = new Array();
617 | }
618 |
619 | BeatDetektor.modules.vis.VU.prototype.process = function(det,lus)
620 | {
621 | var i,det_val,det_max = 0.0;
622 | if (typeof(lus)=='undefined') lus = det.last_update;
623 |
624 | for (i = 0; i < det.config.BD_DETECTION_RANGES; i++)
625 | {
626 | det_val = (det.ma_freq_range[i]/det.maa_freq_range[i]);
627 | if (det_val > det_max) det_max = det_val;
628 | }
629 |
630 | if (det_max <= 0) det_max = 1.0;
631 |
632 | for (i = 0; i < det.config.BD_DETECTION_RANGES; i++)
633 | {
634 | det_val = (det.ma_freq_range[i]/det.maa_freq_range[i]); //fabs(fftData[i*2]/2.0);
635 |
636 | if (det_val != det_val) det_val = 0;
637 |
638 | //&& (det_val > this.vu_levels[i])
639 | if (det_val>1.0)
640 | {
641 | det_val -= 1.0;
642 | if (det_val>1.0) det_val = 1.0;
643 |
644 | if (det_val > this.vu_levels[i])
645 | this.vu_levels[i] = det_val;
646 | else if (det.current_bpm) this.vu_levels[i] -= (this.vu_levels[i]-det_val)*lus*(1.0/det.current_bpm)*3.0;
647 | }
648 | else
649 | {
650 | if (det.current_bpm) this.vu_levels[i] -= (lus/det.current_bpm)*2.0;
651 | }
652 |
653 | if (this.vu_levels[i] < 0 || this.vu_levels[i] != this.vu_levels[i]) this.vu_levels[i] = 0;
654 | }
655 | }
656 |
657 |
658 | // returns vu level for BD_DETECTION_RANGES range[x]
659 | BeatDetektor.modules.vis.VU.prototype.getLevel = function(x)
660 | {
661 | return this.vu_levels[x];
662 | }
--------------------------------------------------------------------------------
/audio_scripts/dsp.js:
--------------------------------------------------------------------------------
1 | /*
2 | * DSP.js - a comprehensive digital signal processing library for javascript
3 | *
4 | * Created by Corban Brook on 2010-01-01.
5 | * Copyright 2010 Corban Brook. All rights reserved.
6 | *
7 | */
8 |
9 | // Setup arrays for platforms which do not support byte arrays
10 | Float32Array = (typeof Float32Array === 'undefined') ? Array : Float32Array;
11 | Float64Array = (typeof Float64Array === 'undefined') ? Array : Float64Array;
12 | Uint32Array = (typeof Uint32Array === 'undefined') ? Array : Uint32Array;
13 |
14 | ////////////////////////////////////////////////////////////////////////////////
15 | // CONSTANTS //
16 | ////////////////////////////////////////////////////////////////////////////////
17 |
18 | /**
19 | * DSP is an object which contains general purpose utility functions and constants
20 | */
21 | DSP = {
22 | // Channels
23 | LEFT: 0,
24 | RIGHT: 1,
25 | MIX: 2,
26 |
27 | // Waveforms
28 | SINE: 1,
29 | TRIANGLE: 2,
30 | SAW: 3,
31 | SQUARE: 4,
32 |
33 | // Filters
34 | LOWPASS: 0,
35 | HIGHPASS: 1,
36 | BANDPASS: 2,
37 | NOTCH: 3,
38 |
39 | // Window functions
40 | BARTLETT: 1,
41 | BARTLETTHANN: 2,
42 | BLACKMAN: 3,
43 | COSINE: 4,
44 | GAUSS: 5,
45 | HAMMING: 6,
46 | HANN: 7,
47 | LANCZOS: 8,
48 | RECTANGULAR: 9,
49 | TRIANGULAR: 10,
50 |
51 | // Loop modes
52 | OFF: 0,
53 | FW: 1,
54 | BW: 2,
55 | FWBW: 3,
56 |
57 | // Math
58 | TWO_PI: 2*Math.PI
59 | };
60 |
61 | ////////////////////////////////////////////////////////////////////////////////
62 | // DSP UTILITY FUNCTIONS //
63 | ////////////////////////////////////////////////////////////////////////////////
64 |
65 | /**
66 | * Inverts the phase of a signal
67 | *
68 | * @param {Array} buffer A sample buffer
69 | *
70 | * @returns The inverted sample buffer
71 | */
72 | DSP.invert = function(buffer) {
73 | for ( var i = 0, len = buffer.length; i < len; i++ ) {
74 | buffer[i] *= -1;
75 | }
76 |
77 | return buffer;
78 | };
79 |
80 | /**
81 | * Converts split-stereo (dual mono) sample buffers into a stereo interleaved sample buffer
82 | *
83 | * @param {Array} left A sample buffer
84 | * @param {Array} right A sample buffer
85 | *
86 | * @returns The stereo interleaved buffer
87 | */
88 | DSP.interleave = function(left, right) {
89 | if ( left.length !== right.length ) {
90 | throw "Can not interleave. Channel lengths differ.";
91 | }
92 |
93 | var stereoInterleaved = new Float32Array(left.length * 2);
94 |
95 | for (var i = 0, len = left.length; i < len; i++ ) {
96 | stereoInterleaved[2*i] = left[i];
97 | stereoInterleaved[2*i+1] = right[i];
98 | }
99 |
100 | return stereoInterleaved;
101 | };
102 |
103 | /**
104 | * Converts a stereo-interleaved sample buffer into split-stereo (dual mono) sample buffers
105 | *
106 | * @param {Array} buffer A stereo-interleaved sample buffer
107 | *
108 | * @returns an Array containing left and right channels
109 | */
110 | DSP.deinterleave = function(buffer) {
111 | var left = new Float32Array(buffer.length/2);
112 | var right = new Float32Array(buffer.length/2);
113 | var mix = new Float32Array(buffer.length/2);
114 |
115 | for (var i = 0, len = buffer.length/2; i < len; i ++ ) {
116 | left[i] = buffer[2*i];
117 | right[i] = buffer[2*i+1];
118 | mix[i] = (left[i] + right[i]) / 2;
119 | }
120 |
121 | return [left, right, mix];
122 | };
123 |
124 | /**
125 | * Separates a channel from a stereo-interleaved sample buffer
126 | *
127 | * @param {Array} buffer A stereo-interleaved sample buffer
128 | * @param {Number} channel A channel constant (LEFT, RIGHT, MIX)
129 | *
130 | * @returns an Array containing a signal mono sample buffer
131 | */
132 | DSP.getChannel = function(channel, buffer) {
133 | return DSP.deinterleave(buffer)[channel];
134 | };
135 |
136 | /**
137 | * DFT is a class for calculating the Discrete Fourier Transform of a signal.
138 | *
139 | * @param {Number} bufferSize The size of the sample buffer to be computed
140 | * @param {Number} sampleRate The sampleRate of the buffer (eg. 44100)
141 | *
142 | * @constructor
143 | */
144 | DFT = function(bufferSize, sampleRate) {
145 | this.bufferSize = bufferSize;
146 | this.sampleRate = sampleRate;
147 |
148 | var N = bufferSize/2 * bufferSize;
149 |
150 | this.sinTable = new Float32Array(N);
151 | this.cosTable = new Float32Array(N);
152 |
153 | for ( var i = 0; i < N; i++ ) {
154 | this.sinTable[i] = Math.sin(i * DSP.TWO_PI / bufferSize);
155 | this.cosTable[i] = Math.cos(i * DSP.TWO_PI / bufferSize);
156 | }
157 |
158 | this.spectrum = new Float32Array(bufferSize/2);
159 | this.complexValues = new Float32Array(bufferSize/2);
160 | };
161 |
162 | /**
163 | * Performs a forward tranform on the sample buffer.
164 | * Converts a time domain signal to frequency domain spectra.
165 | *
166 | * @param {Array} buffer The sample buffer
167 | *
168 | * @returns The frequency spectrum array
169 | */
170 | DFT.prototype.forward = function(buffer) {
171 | var real, imag;
172 |
173 | for ( var k = 0; k < this.bufferSize/2; k++ ) {
174 | real = 0.0;
175 | imag = 0.0;
176 |
177 | for ( var n = 0; n < buffer.length; n++ ) {
178 | real += this.cosTable[k*n] * signal[n];
179 | imag += this.sinTable[k*n] * signal[n];
180 | }
181 |
182 | this.complexValues[k] = {real: real, imag: imag};
183 | }
184 |
185 | for ( var i = 0; i < this.bufferSize/2; i++ ) {
186 | this.spectrum[i] = 2 * Math.sqrt(Math.pow(this.complexValues[i].real, 2) + Math.pow(this.complexValues[i].imag, 2)) / this.bufferSize;
187 | }
188 |
189 | return this.spectrum;
190 | };
191 |
192 |
193 | /**
194 | * FFT is a class for calculating the Discrete Fourier Transform of a signal
195 | * with the Fast Fourier Transform algorithm.
196 | *
197 | * @param {Number} bufferSize The size of the sample buffer to be computed. Must be power of 2
198 | * @param {Number} sampleRate The sampleRate of the buffer (eg. 44100)
199 | *
200 | * @constructor
201 | */
202 | FFT = function(bufferSize, sampleRate) {
203 | this.bufferSize = bufferSize;
204 | this.sampleRate = sampleRate;
205 | this.spectrum = new Float32Array(bufferSize/2);
206 | this.real = new Float32Array(bufferSize);
207 | this.imag = new Float32Array(bufferSize);
208 |
209 | this.reverseTable = new Uint32Array(bufferSize);
210 |
211 | var limit = 1;
212 | var bit = bufferSize >> 1;
213 |
214 | while ( limit < bufferSize ) {
215 | for ( var i = 0; i < limit; i++ ) {
216 | this.reverseTable[i + limit] = this.reverseTable[i] + bit;
217 | }
218 |
219 | limit = limit << 1;
220 | bit = bit >> 1;
221 | }
222 |
223 | this.sinTable = new Float32Array(bufferSize);
224 | this.cosTable = new Float32Array(bufferSize);
225 |
226 | for ( var i = 0; i < bufferSize; i++ ) {
227 | this.sinTable[i] = Math.sin(-Math.PI/i);
228 | this.cosTable[i] = Math.cos(-Math.PI/i);
229 | }
230 | };
231 |
232 | /**
233 | * Performs a forward tranform on the sample buffer.
234 | * Converts a time domain signal to frequency domain spectra.
235 | *
236 | * @param {Array} buffer The sample buffer. Buffer Length must be power of 2
237 | *
238 | * @returns The frequency spectrum array
239 | */
240 | FFT.prototype.forward = function(buffer) {
241 | // Locally scope variables for speed up
242 | var bufferSize = this.bufferSize,
243 | cosTable = this.cosTable,
244 | sinTable = this.sinTable,
245 | reverseTable = this.reverseTable,
246 | real = this.real,
247 | imag = this.imag,
248 | spectrum = this.spectrum;
249 |
250 | if ( bufferSize % 2 !== 0 ) { throw "Invalid buffer size, must be a power of 2."; }
251 | if ( bufferSize !== buffer.length ) { throw "Supplied buffer is not the same size as defined FFT. FFT Size: " + bufferSize + " Buffer Size: " + buffer.length; }
252 |
253 | for ( var i = 0; i < bufferSize; i++ ) {
254 | real[i] = buffer[reverseTable[i]];
255 | imag[i] = 0;
256 | }
257 |
258 | var halfSize = 1,
259 | phaseShiftStepReal,
260 | phaseShiftStepImag,
261 | currentPhaseShiftReal,
262 | currentPhaseShiftImag,
263 | off,
264 | tr,
265 | ti,
266 | tmpReal,
267 | i;
268 |
269 | while ( halfSize < bufferSize ) {
270 | phaseShiftStepReal = cosTable[halfSize];
271 | phaseShiftStepImag = sinTable[halfSize];
272 | currentPhaseShiftReal = 1;
273 | currentPhaseShiftImag = 0;
274 |
275 | for ( var fftStep = 0; fftStep < halfSize; fftStep++ ) {
276 | i = fftStep;
277 |
278 | while ( i < bufferSize ) {
279 | off = i + halfSize;
280 | tr = (currentPhaseShiftReal * real[off]) - (currentPhaseShiftImag * imag[off]);
281 | ti = (currentPhaseShiftReal * imag[off]) + (currentPhaseShiftImag * real[off]);
282 |
283 | real[off] = real[i] - tr;
284 | imag[off] = imag[i] - ti;
285 | real[i] += tr;
286 | imag[i] += ti;
287 |
288 | i += halfSize << 1;
289 | }
290 |
291 | tmpReal = currentPhaseShiftReal;
292 | currentPhaseShiftReal = (tmpReal * phaseShiftStepReal) - (currentPhaseShiftImag * phaseShiftStepImag);
293 | currentPhaseShiftImag = (tmpReal * phaseShiftStepImag) + (currentPhaseShiftImag * phaseShiftStepReal);
294 | }
295 |
296 | halfSize = halfSize << 1;
297 | }
298 |
299 | i = bufferSize/2;
300 | while(i--) {
301 | spectrum[i] = 2 * Math.sqrt(real[i] * real[i] + imag[i] * imag[i]) / bufferSize;
302 | }
303 | };
304 |
305 | Sampler = function Sampler(file, bufferSize, sampleRate, playStart, playEnd, loopStart, loopEnd, loopMode) {
306 | this.file = file;
307 | this.bufferSize = bufferSize;
308 | this.sampleRate = sampleRate;
309 | this.playStart = playStart || 0; // 0%
310 | this.playEnd = playEnd || 1; // 100%
311 | this.loopStart = loopStart || 0;
312 | this.loopEnd = loopEnd || 1;
313 | this.loopMode = loopMode || DSP.OFF;
314 | this.loaded = false;
315 | this.samples = [];
316 | this.signal = new Float32Array(bufferSize);
317 | this.frameCount = 0;
318 | this.envelope = null;
319 | this.amplitude = 1;
320 | this.rootFrequency = 110; // A2 110
321 | this.frequency = 550;
322 | this.step = this.frequency / this.rootFrequency;
323 | this.duration = 0;
324 | this.samplesProcessed = 0;
325 | this.playhead = 0;
326 |
327 | var audio = new Audio();
328 | var self = this;
329 |
330 | this.loadSamples = function(event) {
331 | var buffer = DSP.getChannel(DSP.MIX, event.mozFrameBuffer);
332 | for ( var i = 0; i < buffer.length; i++) {
333 | self.samples.push(buffer[i]);
334 | }
335 | };
336 |
337 | this.loadComplete = function() {
338 | // convert flexible js array into a fast typed array
339 | self.samples = new Float32Array(self.samples);
340 | self.loaded = true;
341 | };
342 |
343 | this.loadMetaData = function() {
344 | self.duration = audio.duration;
345 | };
346 |
347 | audio.src = file;
348 | audio.addEventListener("audiowritten", this.loadSamples, false);
349 | audio.addEventListener("ended", this.loadComplete, false);
350 | audio.addEventListener("loadedmetadata", this.loadMetaData, false)
351 | audio.muted = true;
352 | audio.play();
353 | };
354 |
355 | Sampler.prototype.applyEnvelope = function() {
356 | this.envelope.process(this.signal);
357 | return this.signal;
358 | };
359 |
360 | Sampler.prototype.generate = function() {
361 | var frameOffset = this.frameCount * this.bufferSize;
362 |
363 | var loopWidth = this.playEnd * this.samples.length - this.playStart * this.samples.length;
364 | var playStartSamples = this.playStart * this.samples.length; // ie 0.5 -> 50% of the length
365 | var playEndSamples = this.playEnd * this.samples.length; // ie 0.5 -> 50% of the length
366 | var offset;
367 |
368 | for ( var i = 0; i < this.bufferSize; i++ ) {
369 | switch (this.loopMode) {
370 | case DSP.OFF:
371 | this.playhead = Math.round(this.samplesProcessed * this.step + playStartSamples);
372 | if (this.playhead < (this.playEnd * this.samples.length) ) {
373 | this.signal[i] = this.samples[this.playhead] * this.amplitude;
374 | } else {
375 | this.signal[i] = 0;
376 | }
377 | break;
378 |
379 | case DSP.FW:
380 | this.playhead = Math.round((this.samplesProcessed * this.step) % loopWidth + playStartSamples);
381 | if (this.playhead < (this.playEnd * this.samples.length) ) {
382 | this.signal[i] = this.samples[this.playhead] * this.amplitude;
383 | }
384 | break;
385 |
386 | case DSP.BW:
387 | this.playhead = playEndSamples - Math.round((this.samplesProcessed * this.step) % loopWidth);
388 | if (this.playhead < (this.playEnd * this.samples.length) ) {
389 | this.signal[i] = this.samples[this.playhead] * this.amplitude;
390 | }
391 | break;
392 |
393 | case DSP.FWBW:
394 | if ( Math.floor(this.samplesProcessed * this.step / loopWidth) % 2 == 0 ) {
395 | this.playhead = Math.round((this.samplesProcessed * this.step) % loopWidth + playStartSamples);
396 | } else {
397 | this.playhead = playEndSamples - Math.round((this.samplesProcessed * this.step) % loopWidth);
398 | }
399 | if (this.playhead < (this.playEnd * this.samples.length) ) {
400 | this.signal[i] = this.samples[this.playhead] * this.amplitude;
401 | }
402 | break;
403 | }
404 | this.samplesProcessed++;
405 | }
406 |
407 | this.frameCount++;
408 |
409 | return this.signal;
410 | };
411 |
412 | Sampler.prototype.setFreq = function(frequency) {
413 | this.frequency = frequency;
414 | this.step = this.frequency / this.rootFrequency;
415 | };
416 |
417 | Sampler.prototype.reset = function() {
418 | this.samplesProcessed = 0;
419 | this.playhead = 0;
420 | };
421 |
422 | /**
423 | * Oscillator class for generating and modifying signals
424 | *
425 | * @param {Number} type A waveform constant (eg. DSP.SINE)
426 | * @param {Number} frequency Initial frequency of the signal
427 | * @param {Number} amplitude Initial amplitude of the signal
428 | * @param {Number} bufferSize Size of the sample buffer to generate
429 | * @param {Number} sampleRate The sample rate of the signal
430 | *
431 | * @contructor
432 | */
433 | Oscillator = function Oscillator(type, frequency, amplitude, bufferSize, sampleRate) {
434 | this.frequency = frequency;
435 | this.amplitude = amplitude;
436 | this.bufferSize = bufferSize;
437 | this.sampleRate = sampleRate;
438 | //this.pulseWidth = pulseWidth;
439 | this.frameCount = 0;
440 |
441 | this.waveTableLength = 2048;
442 |
443 | this.cyclesPerSample = frequency / sampleRate;
444 |
445 | this.signal = new Float32Array(bufferSize);
446 | this.envelope = null;
447 |
448 |
449 | switch(parseInt(type)) {
450 | case DSP.TRIANGLE:
451 | this.func = Oscillator.Triangle;
452 | break;
453 |
454 | case DSP.SAW:
455 | this.func = Oscillator.Saw;
456 | break;
457 |
458 | case DSP.SQUARE:
459 | this.func = Oscillator.Square;
460 | break;
461 |
462 | case DSP.SINE:
463 | default:
464 | this.func = Oscillator.Sine;
465 | break;
466 | }
467 |
468 | this.generateWaveTable = function() {
469 | Oscillator.waveTable[this.func] = new Float32Array(2048);
470 | var waveTableTime = this.waveTableLength / this.sampleRate;
471 | var waveTableHz = 1 / waveTableTime;
472 |
473 | for (var i = 0; i < this.waveTableLength; i++) {
474 | Oscillator.waveTable[this.func][i] = this.func(i * waveTableHz/this.sampleRate);
475 | }
476 | };
477 |
478 | if ( typeof Oscillator.waveTable === 'undefined' ) {
479 | Oscillator.waveTable = {};
480 | }
481 |
482 | if ( typeof Oscillator.waveTable[this.func] === 'undefined' ) {
483 | this.generateWaveTable();
484 | }
485 |
486 | this.waveTable = Oscillator.waveTable[this.func];
487 | };
488 |
489 | /**
490 | * Set the amplitude of the signal
491 | *
492 | * @param {Number} amplitude The amplitude of the signal (between 0 and 1)
493 | */
494 | Oscillator.prototype.setAmp = function(amplitude) {
495 | if (amplitude >= 0 && amplitude <= 1) {
496 | this.amplitude = amplitude;
497 | } else {
498 | throw "Amplitude out of range (0..1).";
499 | }
500 | };
501 |
502 | /**
503 | * Set the frequency of the signal
504 | *
505 | * @param {Number} frequency The frequency of the signal
506 | */
507 | Oscillator.prototype.setFreq = function(frequency) {
508 | this.frequency = frequency;
509 | this.cyclesPerSample = frequency / this.sampleRate;
510 | };
511 |
512 | // Add an oscillator
513 | Oscillator.prototype.add = function(oscillator) {
514 | for ( var i = 0; i < this.bufferSize; i++ ) {
515 | //this.signal[i] += oscillator.valueAt(i);
516 | this.signal[i] += oscillator.signal[i];
517 | }
518 |
519 | return this.signal;
520 | };
521 |
522 | // Add a signal to the current generated osc signal
523 | Oscillator.prototype.addSignal = function(signal) {
524 | for ( var i = 0; i < signal.length; i++ ) {
525 | if ( i >= this.bufferSize ) {
526 | break;
527 | }
528 | this.signal[i] += signal[i];
529 |
530 | /*
531 | // Constrain amplitude
532 | if ( this.signal[i] > 1 ) {
533 | this.signal[i] = 1;
534 | } else if ( this.signal[i] < -1 ) {
535 | this.signal[i] = -1;
536 | }
537 | */
538 | }
539 | return this.signal;
540 | };
541 |
542 | // Add an envelope to the oscillator
543 | Oscillator.prototype.addEnvelope = function(envelope) {
544 | this.envelope = envelope;
545 | };
546 |
547 | Oscillator.prototype.applyEnvelope = function() {
548 | this.envelope.process(this.signal);
549 | };
550 |
551 | Oscillator.prototype.valueAt = function(offset) {
552 | return this.waveTable[offset % this.waveTableLength];
553 | };
554 |
555 | Oscillator.prototype.generate = function() {
556 | var frameOffset = this.frameCount * this.bufferSize;
557 | var step = this.waveTableLength * this.frequency / this.sampleRate;
558 | var offset;
559 |
560 | for ( var i = 0; i < this.bufferSize; i++ ) {
561 | //var step = (frameOffset + i) * this.cyclesPerSample % 1;
562 | //this.signal[i] = this.func(step) * this.amplitude;
563 | //this.signal[i] = this.valueAt(Math.round((frameOffset + i) * step)) * this.amplitude;
564 | offset = Math.round((frameOffset + i) * step);
565 | this.signal[i] = this.waveTable[offset % this.waveTableLength] * this.amplitude;
566 | }
567 |
568 | this.frameCount++;
569 |
570 | return this.signal;
571 | };
572 |
573 | Oscillator.Sine = function(step) {
574 | return Math.sin(DSP.TWO_PI * step);
575 | };
576 |
577 | Oscillator.Square = function(step) {
578 | return step < 0.5 ? 1 : -1;
579 | };
580 |
581 | Oscillator.Saw = function(step) {
582 | return 2 * (step - Math.round(step));
583 | };
584 |
585 | Oscillator.Triangle = function(step) {
586 | return 1 - 4 * Math.abs(Math.round(step) - step);
587 | };
588 |
589 | Oscillator.Pulse = function(step) {
590 | // stub
591 | };
592 |
593 | ADSR = function(attackLength, decayLength, sustainLevel, sustainLength, releaseLength, sampleRate) {
594 | this.sampleRate = sampleRate;
595 | // Length in seconds
596 | this.attackLength = attackLength;
597 | this.decayLength = decayLength;
598 | this.sustainLevel = sustainLevel;
599 | this.sustainLength = sustainLength;
600 | this.releaseLength = releaseLength;
601 | this.sampleRate = sampleRate;
602 |
603 | // Length in samples
604 | this.attackSamples = attackLength * sampleRate;
605 | this.decaySamples = decayLength * sampleRate;
606 | this.sustainSamples = sustainLength * sampleRate;
607 | this.releaseSamples = releaseLength * sampleRate;
608 |
609 | // Updates the envelope sample positions
610 | this.update = function() {
611 | this.attack = this.attackSamples;
612 | this.decay = this.attack + this.decaySamples;
613 | this.sustain = this.decay + this.sustainSamples;
614 | this.release = this.sustain + this.releaseSamples;
615 | };
616 |
617 | this.update();
618 |
619 | this.samplesProcessed = 0;
620 | };
621 |
622 |
623 | ADSR.prototype.noteOn = function() {
624 | this.samplesProcessed = 0;
625 | this.sustainSamples = this.sustainLength * this.sampleRate;
626 | this.update();
627 | };
628 |
629 | // Send a note off when using a sustain of infinity to let the envelope enter the release phase
630 | ADSR.prototype.noteOff = function() {
631 | this.sustainSamples = this.samplesProcessed - this.decaySamples;
632 | this.update();
633 | };
634 |
635 | ADSR.prototype.processSample = function(sample) {
636 | var amplitude = 0;
637 |
638 | if ( this.samplesProcessed <= this.attack ) {
639 | amplitude = 0 + (1 - 0) * ((this.samplesProcessed - 0) / (this.attack - 0));
640 | } else if ( this.samplesProcessed > this.attack && this.samplesProcessed <= this.decay ) {
641 | amplitude = 1 + (this.sustainLevel - 1) * ((this.samplesProcessed - this.attack) / (this.decay - this.attack));
642 | } else if ( this.samplesProcessed > this.decay && this.samplesProcessed <= this.sustain ) {
643 | amplitude = this.sustainLevel;
644 | } else if ( this.samplesProcessed > this.sustain && this.samplesProcessed <= this.release ) {
645 | amplitude = this.sustainLevel + (0 - this.sustainLevel) * ((this.samplesProcessed - this.sustain) / (this.release - this.sustain));
646 | }
647 |
648 | return sample * amplitude;
649 | };
650 |
651 | ADSR.prototype.value = function() {
652 | var amplitude = 0;
653 |
654 | if ( this.samplesProcessed <= this.attack ) {
655 | amplitude = 0 + (1 - 0) * ((this.samplesProcessed - 0) / (this.attack - 0));
656 | } else if ( this.samplesProcessed > this.attack && this.samplesProcessed <= this.decay ) {
657 | amplitude = 1 + (this.sustainLevel - 1) * ((this.samplesProcessed - this.attack) / (this.decay - this.attack));
658 | } else if ( this.samplesProcessed > this.decay && this.samplesProcessed <= this.sustain ) {
659 | amplitude = this.sustainLevel;
660 | } else if ( this.samplesProcessed > this.sustain && this.samplesProcessed <= this.release ) {
661 | amplitude = this.sustainLevel + (0 - this.sustainLevel) * ((this.samplesProcessed - this.sustain) / (this.release - this.sustain));
662 | }
663 |
664 | return amplitude;
665 | };
666 |
667 | ADSR.prototype.process = function(buffer) {
668 | for ( var i = 0; i < buffer.length; i++ ) {
669 | buffer[i] *= this.value();
670 |
671 | this.samplesProcessed++;
672 | }
673 |
674 | return buffer;
675 | };
676 |
677 |
678 | ADSR.prototype.isActive = function() {
679 | if ( this.samplesProcessed > this.release || this.samplesProcessed === -1 ) {
680 | return false;
681 | } else {
682 | return true;
683 | }
684 | };
685 |
686 | ADSR.prototype.disable = function() {
687 | this.samplesProcessed = -1;
688 | };
689 |
690 | IIRFilter = function(type, cutoff, resonance, sampleRate) {
691 | this.sampleRate = sampleRate;
692 | this.cutoff = cutoff;
693 | this.resonance = resonance;
694 |
695 | switch(type) {
696 | case DSP.LOWPASS:
697 | case DSP.LP12:
698 | this.func = new IIRFilter.LP12(cutoff, resonance, sampleRate);
699 | break;
700 | }
701 | }
702 |
703 | IIRFilter.prototype.set = function(cutoff, resonance) {
704 | this.func.calcCoeff(cutoff, resonance);
705 | }
706 |
707 | IIRFilter.prototype.process = function(buffer) {
708 | this.func.process(buffer);
709 | }
710 |
711 | // Add an envelope to the filter
712 | IIRFilter.prototype.addEnvelope = function(envelope) {
713 | if ( envelope instanceof ADSR ) {
714 | this.func.addEnvelope(envelope);
715 | } else {
716 | throw "Not an envelope.";
717 | }
718 | };
719 |
720 | IIRFilter.LP12 = function(cutoff, resonance, sampleRate) {
721 | this.sampleRate = sampleRate;
722 | this.vibraPos = 0;
723 | this.vibraSpeed = 0;
724 | this.envelope = false;
725 |
726 | this.calcCoeff = function(cutoff, resonance) {
727 | this.w = 2.0 * Math.PI * cutoff / this.sampleRate;
728 | this.q = 1.0 - this.w / (2.0 * (resonance + 0.5 / (1.0 + this.w)) + this.w - 2.0);
729 | this.r = this.q * this.q;
730 | this.c = this.r + 1.0 - 2.0 * Math.cos(this.w) * this.q;
731 |
732 | this.cutoff = cutoff;
733 | this.resonance = resonance;
734 | };
735 |
736 | this.calcCoeff(cutoff, resonance);
737 |
738 | this.process = function(buffer) {
739 | for ( var i = 0; i < buffer.length; i++ ) {
740 | this.vibraSpeed += (buffer[i] - this.vibraPos) * this.c;
741 | this.vibraPos += this.vibraSpeed;
742 | this.vibraSpeed *= this.r;
743 |
744 | /*
745 | var temp = this.vibraPos;
746 |
747 | if ( temp > 1.0 ) {
748 | temp = 1.0;
749 | } else if ( temp < -1.0 ) {
750 | temp = -1.0;
751 | } else if ( temp != temp ) {
752 | temp = 1;
753 | }
754 |
755 | buffer[i] = temp;
756 | */
757 |
758 | if (this.envelope) {
759 | buffer[i] = (buffer[i] * (1 - this.envelope.value())) + (this.vibraPos * this.envelope.value());
760 | this.envelope.samplesProcessed++;
761 | } else {
762 | buffer[i] = this.vibraPos;
763 | }
764 | }
765 | }
766 | };
767 |
768 | IIRFilter.LP12.prototype.addEnvelope = function(envelope) {
769 | this.envelope = envelope;
770 | };
771 |
772 | IIRFilter2 = function(type, cutoff, resonance, sampleRate) {
773 | this.type = type;
774 | this.cutoff = cutoff;
775 | this.resonance = resonance;
776 | this.sampleRate = sampleRate;
777 |
778 | this.calcCoeff = function(cutoff, resonance) {
779 | this.freq = 2 * Math.sin(Math.PI * Math.min(0.25, cutoff/(this.sampleRate*2)));
780 | this.damp = Math.min(2 * (1 - Math.pow(resonance, 0.25)), Math.min(2, 2/this.freq - this.freq * 0.5));
781 | };
782 |
783 | this.calcCoeff(cutoff, resonance);
784 | };
785 |
786 | IIRFilter2.prototype.process = function(buffer) {
787 | var input, output, lp, hp, bp, br;
788 |
789 | var f = Array(4);
790 | f[0] = 0; // lp
791 | f[1] = 0; // hp
792 | f[2] = 0; // bp
793 | f[3] = 0; // br
794 |
795 | for ( var i = 0; i < buffer.length; i++ ) {
796 | input = buffer[i];
797 |
798 | // first pass
799 | f[3] = input - this.damp * f[2];
800 | f[0] = f[0] + this.freq * f[2];
801 | f[1] = f[3] - f[0];
802 | f[2] = this.freq * f[1] + f[2];
803 | output = 0.5 * f[this.type];
804 |
805 | // second pass
806 | f[3] = input - this.damp * f[2];
807 | f[0] = f[0] + this.freq * f[2];
808 | f[1] = f[3] - f[0];
809 | f[2] = this.freq * f[1] + f[2];
810 | output += 0.5 * f[this.type];
811 |
812 | if (this.envelope) {
813 | buffer[i] = (buffer[i] * (1 - this.envelope.value())) + (output * this.envelope.value());
814 | this.envelope.samplesProcessed++;
815 | } else {
816 | buffer[i] = output;
817 | }
818 | }
819 | };
820 |
821 | IIRFilter2.prototype.addEnvelope = function(envelope) {
822 | if ( envelope instanceof ADSR ) {
823 | this.envelope = envelope;
824 | } else {
825 | throw "This is not an envelope.";
826 | }
827 | };
828 |
829 | IIRFilter2.prototype.set = function(cutoff, resonance) {
830 | this.calcCoeff(cutoff, resonance);
831 | };
832 |
833 | WindowFunction = function(type, alpha) {
834 | this.alpha = alpha;
835 |
836 | switch(type) {
837 | case DSP.BARTLETT:
838 | this.func = WindowFunction.Bartlett;
839 | break;
840 |
841 | case DSP.BARTLETTHANN:
842 | this.func = WindowFunction.BartlettHann;
843 | break;
844 |
845 | case DSP.BLACKMAN:
846 | this.func = WindowFunction.Blackman;
847 | this.alpha = this.alpha || 0.16;
848 | break;
849 |
850 | case DSP.COSINE:
851 | this.func = WindowFunction.Cosine;
852 | break;
853 |
854 | case DSP.GAUSS:
855 | this.func = WindowFunction.Gauss;
856 | this.alpha = this.alpha || 0.25;
857 | break;
858 |
859 | case DSP.HAMMING:
860 | this.func = WindowFunction.Hamming;
861 | break;
862 |
863 | case DSP.HANN:
864 | this.func = WindowFunction.Hann;
865 | break;
866 |
867 | case DSP.LANCZOS:
868 | this.func = WindowFunction.Lanczoz;
869 | break;
870 |
871 | case DSP.RECTANGULAR:
872 | this.func = WindowFunction.Rectangular;
873 | break;
874 |
875 | case DSP.TRIANGULAR:
876 | this.func = WindowFunction.Triangular;
877 | break;
878 | }
879 | };
880 |
881 | WindowFunction.prototype.process = function(buffer) {
882 | var length = buffer.length;
883 | for ( var i = 0; i < length; i++ ) {
884 | buffer[i] *= this.func(length, i, this.alpha);
885 | }
886 | };
887 |
888 | WindowFunction.Bartlett = function(length, index) {
889 | return 2 / (length - 1) * ((length - 1) / 2 - Math.abs(index - (length - 1) / 2));
890 | };
891 |
892 | WindowFunction.BartlettHann = function(length, index) {
893 | return 0.62 - 0.48 * Math.abs(index / (length - 1) - 0.5) - 0.38 * Math.cos(DSP.TWO_PI * index / (length - 1));
894 | };
895 |
896 | WindowFunction.Blackman = function(length, index, alpha) {
897 | var a0 = (1 - alpha) / 2;
898 | var a1 = 0.5;
899 | var a2 = alpha / 2;
900 |
901 | return a0 - a1 * Math.cos(DSP.TWO_PI * index / (length - 1)) + a2 * Math.cos(4 * Math.PI * index / (length - 1));
902 | };
903 |
904 | WindowFunction.Cosine = function(length, index) {
905 | return Math.cos(Math.PI * index / (length - 1) - Math.PI / 2);
906 | };
907 |
908 | WindowFunction.Gauss = function(length, index, alpha) {
909 | return Math.pow(Math.E, -0.5 * Math.pow((index - (length - 1) / 2) / (alpha * (length - 1) / 2), 2));
910 | };
911 |
912 | WindowFunction.Hamming = function(length, index) {
913 | return 0.54 - 0.46 * Math.cos(DSP.TWO_PI * index / (length - 1));
914 | };
915 |
916 | WindowFunction.Hann = function(length, index) {
917 | return 0.5 * (1 - Math.cos(DSP.TWO_PI * index / (length - 1)));
918 | };
919 |
920 | WindowFunction.Lanczos = function(length, index) {
921 | var x = 2 * index / (length - 1) - 1;
922 | return Math.sin(Math.PI * x) / (Math.PI * x);
923 | };
924 |
925 | WindowFunction.Rectangular = function(length, index) {
926 | return 1;
927 | };
928 |
929 | WindowFunction.Triangular = function(length, index) {
930 | return 2 / length * (length / 2 - Math.abs(index - (length - 1) / 2));
931 | };
932 |
--------------------------------------------------------------------------------
/audio_scripts/main.js:
--------------------------------------------------------------------------------
1 | var frameSize = 2048,
2 | bufferSize = frameSize / 2,
3 | sampleRate = 44100,
4 | signal = new Float32Array(bufferSize),
5 | fft = new FFT(bufferSize, sampleRate),
6 | bd = new BeatDetektor(60, 90),
7 | vu = new BeatDetektor.modules.vis.VU(),
8 | m_BeatCounter = 0,
9 | m_BeatTimer = 0,
10 | clearClr = [0,0,1],
11 | ftimer = 0,
12 | audio;
13 |
14 | window.addEventListener("load", function() {
15 | audio = document.getElementById("grappes");
16 | audio.addEventListener('MozAudioAvailable', audioAvailable, false);
17 | }, true);
18 |
19 | function startProcessingAudio() {
20 | Processing.getInstanceById("audiocube").loop();
21 | audio.play();
22 | }
23 |
24 | function stopProcessingAudio() {
25 | Processing.getInstanceById("audiocube").noLoop();
26 | audio.pause();
27 | }
28 |
29 | function audioAvailable(event) {
30 | var frameBuffer = event.frameBuffer;
31 | timestamp = event.time;
32 | // de-interleave and mix down to mono
33 | signal = DSP.getChannel(DSP.MIX, frameBuffer);
34 | // perform forward transform
35 | fft.forward(signal);
36 | // beat detection
37 | bd.process( timestamp, fft.spectrum );
38 | ftimer += bd.last_update;
39 | if (ftimer > 1.0/24.0) {
40 | vu.process(bd,ftimer);
41 | ftimer = 0;
42 | }
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/demos.css:
--------------------------------------------------------------------------------
1 | /* SOME SPECIFIC LAYOUTS */
2 |
3 | article, section {display: block;}
4 |
5 | .parser { width: 140px; text-align: center}
6 | .parser > * { vertical-align: middle; display: inline; }
7 |
8 | .canvas2d:after { content: url(imgs/overlay.png)!important; position: absolute; top: 0; left: 0; pointer-events: none; z-index: 65000; background-color: transparent}
9 | .canvas2d canvas { width: 150px; }
10 |
11 | #audiodemo > .demo,
12 | #audiodemo > .demo > canvas { width: 100px; height: 100px; }
13 |
14 | #tagsoup .demo p { text-align: left;}
15 | #tagsoup .demo span { font-family: bebas; }
16 | #tagsoup:hover > .demo { top: 30px!important; }
17 |
18 | #fontfacedemo {width: 170px; float: right; margin-left: 10px;}
19 | #fontfacedemo * { margin: 0; padding: 0; vertical-align: top;}
20 | #fontfacedemo span {font-size: 18px; letter-spacing: -1px; display: inline-block;}
21 |
22 | #radiusdemo { transition-duration: 3s;-moz-transition-duration: 3s;-webkit-transition-duration: 3s; border: 1px solid transparent; max-width: 220px; border-top: 1px solid transparent!important; }
23 | #radiusdemo:hover { border: 1px solid black; border-top: 1px solid black!important; border-radius: 35px;}
24 |
25 | #gradientdemo:hover {
26 | background-image: -moz-radial-gradient(50% 120%, circle, white, rgba(40, 194, 218, 1) 40%, rgba(0, 194, 218, 0) 60%) , url("imgs/texture.png") !important;
27 | background-image: -webkit-radial-gradient(50% 120%, circle, white, rgba(40, 194, 218, 1) 40%, rgba(0, 194, 218, 0) 60%) , url("imgs/texture.png") !important;
28 | }
29 |
30 | #geodemo .demo.showme { top: 40px; }
31 |
32 | #orientationdemo .demo {padding: 10px;}
33 |
34 | .dnding #dnddemo .demo {top: 100px;}
35 | #dnddemo .demo img {width: 200px;}
36 | #dnddemo .demo {text-align: center; padding: 5px;}
37 |
38 | #dragdemo {background-color: #E1E6E9; cursor: pointer;}
39 | #dragdemo .demo {width: 200px;}
40 |
41 | #columndemo {width: 245px!important; padding-right: 10px!important;}
42 | #columndemo > p {-moz-column-count: 2; text-align: left!important;}
43 |
44 | #boxshadowdemo { box-shadow: inset 0px 0px 0px black; transition-duration: 0.4s; -moz-transition-duration: 0.4s; -webkit-transition-duration: 0.4s; -webkit-box-shadow: inset 0px 0px 0px black; }
45 | #boxshadowdemo:hover { box-shadow: inset 0px 0px 100px black; -webkit-box-shadow: inset 0px 0px 100px black; }
46 |
47 | #textshadowdemo > div { padding: 10px; }
48 | #textshadowdemo > .demo {background-color: #E1E6E9!important;}
49 | #textshadowdemo > div > p { color: white; font-family: bebas; font-size: 25px; text-shadow: 0px 0px 4px black; }
50 |
51 | #transformdemo p { transition-duration: 1.4s;-moz-transition-duration: 1.4s;-webkit-transition-duration: 1.4s; }
52 | #transformdemo:hover p { -moz-transform: rotate(900deg) scale(-1, -1); -webkit-transform: rotate(900deg) scale(-1, -1);}
53 |
54 | #transitiondemo { background-color: transparent!important;
55 | border-width: 0!important;
56 | -webkit-box-shadow: none!important;
57 | -moz-box-shadow: none!important;
58 | font-family: ubuntu;
59 | font-size: 60px;
60 | display: block;
61 | text-align: center;
62 | margin: auto;
63 | text-shadow: 0px 0px 5px black;
64 | color: rgba(0, 0, 0, 0);
65 | margin-top: 20px;
66 | -webkit-transition-duration: 1s!important;
67 | -moz-transition-duration: 6s!important;
68 | -moz-transition-timing-function: cubic-bezier(0.05, 1.6, 0.25, 1);
69 | }
70 | #transitiondemo:hover { -webkit-transform: scale(3) rotate(360deg); -moz-transform: scale(3) rotate(360deg); text-shadow: 0px 0px 3px #28C2DA; }
71 |
72 | #formdemo input { display: inline; width: 70px; border: none; font-size: 12px; box-shadow: 0px 0px 5px #28C2DA; }
73 | #formdemo button { box-shadow: 0px 0px 5px #28C2DA; background-color: white; color: #28C2DA; border: none; font-weight: bold; float: right; }
74 | #formdemo em { display: block; margin-top: 20px; vertical-align: middle; }
75 | #formdemo input:last-of-type { width: 90px;}
76 | #formdemo .demo { padding: 3px; width: 160px; font-size: 12px;}
77 | #formdemo:not(.submited) .demo > p {display: none;}
78 | #formdemo:not(.submited) .demo > form {display: inline;}
79 | #formdemo.submited .demo > p {display: block;}
80 | #formdemo.submited .demo > form {display: none;}
81 |
82 | #multiplatform img {width: 150px; display: block; margin-top: 80px;}
83 |
84 | .nogl #webgldemo .demo {display: none;}
85 | #webgldemo canvas { transition-duration: 1s; -webkit-transition-duration: 1s; -moz-transition-duration: 1s; width: 150px; height: 100px; transition-delay: 1s; -webkit-transition-delay: 1s; -moz-transition-delay: 1s; z-index: 10000;}
86 | #webgldemo canvas:hover { transform: scale(2); -webkit-transform: scale(2); -moz-transform: scale(2);}
87 |
88 | #borderimagedemo {transition: none;-webkit-transition: none;-moz-transition: none;}
89 | #borderimagedemo:hover { -webkit-border-image: url(imgs/tv-border.jpg) 25 31 37 31 stretch stretch; -moz-border-image: url(imgs/tv-border.jpg) 25 31 37 31 stretch stretch; border-width: 20px!important; background-color: white!important; color: white; padding: 10px!important; max-height: 210px; }
90 | #borderimagedemo:hover p {margin-top: 40px;}
91 | #borderimagedemo:hover h1 {top: 20px;}
92 |
93 | #mozelementdemo {
94 | background-image: -moz-element(#overview);
95 | background-size: 100% 30%;
96 | background-repeat: no-repeat;
97 | background-position: 0 170px;
98 | }
99 |
100 | #ffsdemo:hover .demo {top: 30px!important;}
101 | #ffsdemo .demo { font-family: megalopolis; font-size: 15px; text-align: center;}
102 | .dlig { -moz-font-feature-settings: "dlig=1"; }
103 | .dlig-ss01 { -moz-font-feature-settings: "dlig=1,ss01=1"; }
104 | .dlig-ss02 { -moz-font-feature-settings: "dlig=1,ss02=1,case=1"; }
105 | .ss04 { -moz-font-feature-settings: "ss04=1"; }
106 | .ss05 { -moz-font-feature-settings: "ss05=1"; }
107 | .ss06 { -moz-font-feature-settings: "ss06=1"; letter-spacing: -1px; }
108 | .salt { -moz-font-feature-settings: "salt=1"; }
109 |
110 | /*
111 | * Project: circular player
112 | * http://www.jplayer.org
113 | * Copyright (c) 2011 Happyworm Ltd
114 | * Author: Silvia Benvenuti
115 | * Date: 18th January 2011
116 | * Arwork inspired by: http://forrst.com/posts/Untitled-CJz
117 | */
118 | .player :focus { border:none; outline:0; }
119 | #jquery_jplayer_1 { width: 0; height: 0; }
120 | .player { width: 200px; height: 200px; background: url("imgs/bgr.jpg") 0 0 no-repeat; margin: 0 auto; padding: 48px; }
121 | #audioplayerdemo > .demo { height: 200px;}
122 | #audioplayerdemo:hover > .demo { top: 30px;}
123 | #jp_interface_1 { width: 100px; height: 100px; overflow: hidden; }
124 | .progress { position: absolute; top: 0; left: 0; width: 104px; height: 104px; background: url("imgs/progress.png") 0 0 no-repeat; clip:rect(0px,52px,104px,0px); -moz-border-radius:52px; -webkit-border-radius:52px; border-radius:52px; -moz-transform:rotate(0); -webkit-transform:rotate(0); -o-transform:rotate(0); transform:rotate(0); /* NO CSS3 FALLBACK (12 steps starting from 1hr filled progress, DEcrease second value by 104px for next step) background: url("graphics/progress_sprite.jpg") 0 0 no-repeat; */ }
125 | /* this is needed when progress is greater than 50% */ .progress.fill { -moz-transform:rotate(0deg); -webkit-transform:rotate(0deg); transform:rotate(0deg); -o-transform:rotate(0deg); }
126 | .hold, .click-control { position:absolute; width:104px; height:104px; }
127 | .click-control:hover { cursor:pointer; }
128 | .hold { clip:rect(0px,104px,104px,52px); }
129 | /* this is needed when progress is greater than 50% */ .hold.gt50 { clip:rect(auto, auto, auto, auto); }
130 | .jp-controls { margin:26px; padding: 0; }
131 | .jp-controls li{ list-style-type:none; display: block; }
132 | .jp-controls li a{ position: relative; display: block; width:50px; height:50px; text-indent:-9999px; z-index:1; }
133 | .jp-controls .jp-play { background: url("imgs/controls.jpg") 0 0 no-repeat; }
134 | .jp-controls .jp-play:hover { background: url("imgs/controls.jpg") -50px 0 no-repeat; cursor:pointer; }
135 | .jp-controls .jp-pause { background: url("imgs/controls.jpg") 0 -50px no-repeat; }
136 | .jp-controls .jp-pause:hover { background: url("imgs/controls.jpg") -50px -50px no-repeat; }
137 |
138 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/fonts/BebasNeue.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/fonts/BebasNeue.otf
--------------------------------------------------------------------------------
/fonts/MEgalopolisExtra.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/fonts/MEgalopolisExtra.woff
--------------------------------------------------------------------------------
/fonts/MarketingScript.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/fonts/MarketingScript.ttf
--------------------------------------------------------------------------------
/fonts/ubuntu.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/fonts/ubuntu.ttf
--------------------------------------------------------------------------------
/imgs/bgr.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/bgr.jpg
--------------------------------------------------------------------------------
/imgs/close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/close.png
--------------------------------------------------------------------------------
/imgs/controls.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/controls.jpg
--------------------------------------------------------------------------------
/imgs/dashed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/dashed.png
--------------------------------------------------------------------------------
/imgs/link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/link.png
--------------------------------------------------------------------------------
/imgs/lion.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
162 |
--------------------------------------------------------------------------------
/imgs/overlay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/overlay.png
--------------------------------------------------------------------------------
/imgs/phial.svg:
--------------------------------------------------------------------------------
1 |
33 |
--------------------------------------------------------------------------------
/imgs/progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/progress.png
--------------------------------------------------------------------------------
/imgs/texture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/texture.png
--------------------------------------------------------------------------------
/imgs/throbber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/throbber.gif
--------------------------------------------------------------------------------
/imgs/tv-border.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/tv-border.jpg
--------------------------------------------------------------------------------
/imgs/whiteButton.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/imgs/whiteButton.png
--------------------------------------------------------------------------------
/logos/android.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/logos/android.png
--------------------------------------------------------------------------------
/logos/apple.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/logos/apple.png
--------------------------------------------------------------------------------
/logos/linux.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/logos/linux.png
--------------------------------------------------------------------------------
/logos/maemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/logos/maemo.png
--------------------------------------------------------------------------------
/logos/meego.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/logos/meego.png
--------------------------------------------------------------------------------
/logos/w3c.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/logos/w3c.png
--------------------------------------------------------------------------------
/logos/webm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/logos/webm.png
--------------------------------------------------------------------------------
/logos/windows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/logos/windows.png
--------------------------------------------------------------------------------
/logos/xiph.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/logos/xiph.png
--------------------------------------------------------------------------------
/media/enfants.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/media/enfants.webm
--------------------------------------------------------------------------------
/media/track.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/media/track.ogg
--------------------------------------------------------------------------------
/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/screenshot.jpg
--------------------------------------------------------------------------------
/scripts/audioplayer.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function(){
2 |
3 | var myPlayer = $("#jquery_jplayer_1");
4 |
5 | myPlayer.jPlayer({
6 | ready: function () {
7 | $(this).jPlayer("setMedia", {
8 | oga: "media/track.ogg"
9 | });
10 | },
11 | swfPath: "js",
12 | supplied: "oga"
13 | });
14 |
15 | function displayProgress(pc) {
16 | var degs = pc * 3.6+"deg";
17 |
18 | if (pc <= 50) {
19 | $('#circle-holder').removeClass('gt50');
20 | $('#progress1').css({rotate: degs});
21 | $('#progress2').hide();
22 | }
23 | else if (pc < 100) {
24 | $('#circle-holder').addClass('gt50');
25 | $('#progress1').css({rotate: '180deg'});
26 | $('#progress2').show();
27 | $('#progress2').css({rotate: degs});
28 | }
29 | }
30 |
31 | myPlayer.bind($.jPlayer.event.timeupdate, function(event) {
32 | var pc = event.jPlayer.status.currentPercentAbsolute;
33 | displayProgress(pc);
34 | });
35 |
36 | myPlayer.bind($.jPlayer.event.ended, function() {
37 | $('#circle-holder').removeClass('gt50');
38 | $('#progress1').css({rotate: '0deg'}).show();
39 | $('#progress2').css({rotate: '0deg'}).hide();
40 | });
41 |
42 | $('.click-control').click(function(event) {
43 | var self = $(this);
44 | var x = event.pageX - self.offset().left - self.width()/2;
45 | var y = event.pageY - self.offset().top - self.height()/2;
46 |
47 | var a = Math.atan2(y,x);
48 | if (a > -1*Math.PI && a < -0.5*Math.PI) {
49 | a = 2*Math.PI+a;
50 | }
51 |
52 | // a is now value between -0.5PI and 1.5PI
53 | // ready to be normalized and applied
54 |
55 | var pc = (a + Math.PI/2) / 2*Math.PI * 10;
56 |
57 | myPlayer.jPlayer("playHead", pc).jPlayer("play");
58 |
59 | return false;
60 | });
61 |
62 | });
63 |
--------------------------------------------------------------------------------
/scripts/canvas2d.js:
--------------------------------------------------------------------------------
1 | function chain( func ) { return function() { return func.apply( this, arguments )||this; } }
2 | CanvasRenderingContext2D.prototype.set = function( what, to ) { this[what] = to; }
3 | for( chainThat in {set:1,clearRect:1,save:1,translate:1,rotate:1,drawImage:1,scale:1,restore:1,fillRect:1,moveTo:1,lineTo:1,beginPath:1,closePath:1,stroke:1,fill:1,arc:1} ) { CanvasRenderingContext2D.prototype[chainThat] = chain( CanvasRenderingContext2D.prototype[chainThat] ); }
4 | onmousemove = function( event ) { window.mouse = [ (window.event||event).screenX, (window.event||event).screenY ]; }
5 |
6 | window.addEventListener("load", function() {
7 | var canvas = document.getElementById('canvas2d');
8 | var interval;
9 |
10 | for (var i = 0; i < 60; i++) {tick()};
11 |
12 | canvas.addEventListener("mouseout", function() { if (interval) clearInterval(interval); }, true);
13 | canvas.addEventListener("mouseover", function() { interval = setInterval(tick, 50 );} , true);
14 |
15 | function tick() {
16 | //By http://www.p01.org/news/
17 | //From http://www.p01.org/releases/20_lines_twinkle/
18 |
19 | var now = new Date().getTime()+(window.mouse||[0,0])[0]*2-200;
20 |
21 | var canvas = document.getElementById('canvas2d');
22 | var ctx = canvas.getContext('2d');
23 |
24 | ctx.globalCompositeOperation = 'copy';
25 | ctx.drawImage(canvas, 12+Math.cos(now/806+(window.mouse||[0,0])[0]/128),8+Math.sin(now/551+(window.mouse||[0,0])[1]/128),240-24,160-16,0,0,240,160);
26 | ctx.globalCompositeOperation = 'source-over';
27 |
28 | ctx.beginPath();
29 | ctx.fillStyle = "black";
30 | ctx.arc(120,80,12,0,Math.PI * 2, .628,0);
31 | ctx.closePath();
32 | ctx.fill();
33 |
34 | var colors = ["#28C2DA", "white", "black", "#2EC4DD"];
35 |
36 | for( var j=0; j<10; j++ ) {
37 | var a = j/1.59+((Math.cos(now/1337)+now/4096)%1.2566);
38 | ctx.beginPath();
39 | ctx.moveTo(120-Math.sin(now/618),80+Math.cos(now/523));
40 | ctx.arc(120,80,12,a,a+.628,0);
41 | ctx.closePath();
42 | ctx.fillStyle = colors[Math.round(Math.random() * colors.length)];//'#'+('00'+(Math.random()*0xfff&(j&1?0x17f:0xf31)).toString(16)).slice(-3);
43 | ctx.fill();
44 | }
45 | }
46 | }, true);
47 |
--------------------------------------------------------------------------------
/scripts/classList.js:
--------------------------------------------------------------------------------
1 | /*
2 | * classList.js: Implements a cross-browser element.classList getter.
3 | * 2011-01-24
4 | *
5 | * By Eli Grey, http://eligrey.com
6 | * Public Domain.
7 | * NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8 | */
9 |
10 | if (typeof Element !== "undefined" && !Element.prototype.hasOwnProperty("classList")) {
11 |
12 | (function () {
13 |
14 | var
15 | classListProp = "classList"
16 | , protoProp = "prototype"
17 | , elemCtrProto = Element[protoProp]
18 | , objCtr = Object
19 | strTrim = String[protoProp].trim || function () {
20 | return this.replace(/^\s+|\s+$/g, "");
21 | }
22 | , arrIndexOf = Array[protoProp].indexOf || function (item) {
23 | for (var i = 0, len = this.length; i < len; i++) {
24 | if (i in this && this[i] === item) {
25 | return i;
26 | }
27 | }
28 | return -1;
29 | }
30 | // Vendors: please allow content code to instantiate DOMExceptions
31 | , DOMEx = function (type, message) {
32 | this.name = type;
33 | this.code = DOMException[type];
34 | this.message = message;
35 | }
36 | , checkTokenAndGetIndex = function (classList, token) {
37 | if (token === "") {
38 | throw new DOMEx(
39 | "SYNTAX_ERR"
40 | , "An invalid or illegal string was specified"
41 | );
42 | }
43 | if (/\s/.test(token)) {
44 | throw new DOMEx(
45 | "INVALID_CHARACTER_ERR"
46 | , "String contains an invalid character"
47 | );
48 | }
49 | return arrIndexOf.call(classList, token);
50 | }
51 | , ClassList = function (elem) {
52 | var
53 | trimmedClasses = strTrim.call(elem.className)
54 | , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
55 | ;
56 | for (var i = 0, len = classes.length; i < len; i++) {
57 | this.push(classes[i]);
58 | }
59 | this._updateClassName = function () {
60 | elem.className = this.toString();
61 | };
62 | }
63 | , classListProto = ClassList[protoProp] = []
64 | , classListGetter = function () {
65 | return new ClassList(this);
66 | }
67 | ;
68 | // Most DOMException implementations don't allow calling DOMException's toString()
69 | // on non-DOMExceptions. Error's toString() is sufficient here.
70 | DOMEx[protoProp] = Error[protoProp];
71 | classListProto.item = function (i) {
72 | return this[i] || null;
73 | };
74 | classListProto.contains = function (token) {
75 | token += "";
76 | return checkTokenAndGetIndex(this, token) !== -1;
77 | };
78 | classListProto.add = function (token) {
79 | token += "";
80 | if (checkTokenAndGetIndex(this, token) === -1) {
81 | this.push(token);
82 | this._updateClassName();
83 | }
84 | };
85 | classListProto.remove = function (token) {
86 | token += "";
87 | var index = checkTokenAndGetIndex(this, token);
88 | if (index !== -1) {
89 | this.splice(index, 1);
90 | this._updateClassName();
91 | }
92 | };
93 | classListProto.toggle = function (token) {
94 | token += "";
95 | if (checkTokenAndGetIndex(this, token) === -1) {
96 | this.add(token);
97 | } else {
98 | this.remove(token);
99 | }
100 | };
101 | classListProto.toString = function () {
102 | return this.join(" ");
103 | };
104 |
105 | if (objCtr.defineProperty) {
106 | var classListDescriptor = {
107 | get: classListGetter
108 | , enumerable: true
109 | , configurable: true
110 | };
111 | try {
112 | objCtr.defineProperty(elemCtrProto, classListProp, classListDescriptor);
113 | } catch (ex) { // IE 8 doesn't support enumerable:true
114 | if (ex.number === -0x7FF5EC54) {
115 | classListDescriptor.enumerable = false;
116 | objCtr.defineProperty(elemCtrProto, classListProp, classListDescriptor);
117 | }
118 | }
119 | } else if (objCtr[protoProp].__defineGetter__) {
120 | elemCtrProto.__defineGetter__(classListProp, classListGetter);
121 | }
122 |
123 | }());
124 |
125 | }
126 |
--------------------------------------------------------------------------------
/scripts/dnd.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("load", function() {
2 |
3 | var s = document.querySelector("#dnddemo");
4 | var initialized = false;
5 |
6 | function dragenter(e) {
7 | document.body.classList.add("dnding");
8 | e.stopPropagation();
9 | e.preventDefault();
10 | }
11 | function dragleave(e) {
12 | e.stopPropagation();
13 | e.preventDefault();
14 | }
15 | function dragover(e) { e.stopPropagation(); e.preventDefault(); }
16 |
17 | function filesdropped(e) {
18 | document.body.classList.remove("dnding");
19 |
20 | e.stopPropagation();
21 | e.preventDefault();
22 |
23 | if (e.dataTransfer.files.length == 0) return;
24 |
25 | var file = e.dataTransfer.files[0];
26 | var reader = new FileReader();
27 | reader.readAsDataURL(file);
28 | reader.onload = (function(file) {
29 | return function(e) {
30 | var url = e.target.result;
31 | var img = document.querySelector("#dnddemo img");
32 | img.src = url;
33 | }})(file);
34 | }
35 | window.addEventListener("dragenter", dragenter, true);
36 | window.addEventListener("dragleave", dragleave, true);
37 | window.addEventListener("dragover", dragover, true);
38 | s.addEventListener("drop", filesdropped, true);
39 | }, true);
40 |
--------------------------------------------------------------------------------
/scripts/geolocation.js:
--------------------------------------------------------------------------------
1 | function geo_success(position) {
2 | var mapcanvas = document.createElement('div');
3 | mapcanvas.id = 'mapcanvas';
4 | mapcanvas.style.height = '200px';
5 | mapcanvas.style.width = '200px';
6 |
7 | var demo = document.querySelector('#geodemo .demo');
8 | demo.appendChild(mapcanvas);
9 | demo.querySelector("button").style.display = "none";
10 |
11 | var latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
12 | var myOptions = {
13 | zoom: 15,
14 | center: latlng,
15 | mapTypeControl: false,
16 | navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL},
17 | mapTypeId: google.maps.MapTypeId.ROADMAP
18 | };
19 | var map = new google.maps.Map(mapcanvas, myOptions);
20 |
21 | var marker = new google.maps.Marker({
22 | position: latlng,
23 | map: map,
24 | title:"You are here!"
25 | });
26 | }
27 |
28 | function getCoords() {
29 | var demo = document.querySelector('#geodemo .demo');
30 | demo.classList.add("showme");
31 | window.addEventListener("click", function() {
32 | demo.classList.remove("showme");
33 | window.removeEventListener("click", arguments.callee, true);
34 | }, true);
35 |
36 | navigator.geolocation.getCurrentPosition(geo_success, function() {console.log("geo error")});
37 | }
38 |
--------------------------------------------------------------------------------
/scripts/jquery.jplayer.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jPlayer Plugin for jQuery JavaScript Library
3 | * http://www.happyworm.com/jquery/jplayer
4 | *
5 | * Copyright (c) 2009 - 2010 Happyworm Ltd
6 | * Dual licensed under the MIT and GPL licenses.
7 | * - http://www.opensource.org/licenses/mit-license.php
8 | * - http://www.gnu.org/copyleft/gpl.html
9 | *
10 | * Author: Mark J Panaghiston
11 | * Version: 2.0.0
12 | * Date: 20th December 2010
13 | */
14 |
15 | (function(c,h){c.fn.jPlayer=function(a){var b=typeof a==="string",d=Array.prototype.slice.call(arguments,1),f=this;a=!b&&d.length?c.extend.apply(null,[true,a].concat(d)):a;if(b&&a.charAt(0)==="_")return f;b?this.each(function(){var e=c.data(this,"jPlayer"),g=e&&c.isFunction(e[a])?e[a].apply(e,d):e;if(g!==e&&g!==h){f=g;return false}}):this.each(function(){var e=c.data(this,"jPlayer");if(e){e.option(a||{})._init();e.option(a||{})}else c.data(this,"jPlayer",new c.jPlayer(a,this))});return f};c.jPlayer=
16 | function(a,b){if(arguments.length){this.element=c(b);this.options=c.extend(true,{},this.options,a);var d=this;this.element.bind("remove.jPlayer",function(){d.destroy()});this._init()}};c.jPlayer.event={ready:"jPlayer_ready",resize:"jPlayer_resize",error:"jPlayer_error",warning:"jPlayer_warning",loadstart:"jPlayer_loadstart",progress:"jPlayer_progress",suspend:"jPlayer_suspend",abort:"jPlayer_abort",emptied:"jPlayer_emptied",stalled:"jPlayer_stalled",play:"jPlayer_play",pause:"jPlayer_pause",loadedmetadata:"jPlayer_loadedmetadata",
17 | loadeddata:"jPlayer_loadeddata",waiting:"jPlayer_waiting",playing:"jPlayer_playing",canplay:"jPlayer_canplay",canplaythrough:"jPlayer_canplaythrough",seeking:"jPlayer_seeking",seeked:"jPlayer_seeked",timeupdate:"jPlayer_timeupdate",ended:"jPlayer_ended",ratechange:"jPlayer_ratechange",durationchange:"jPlayer_durationchange",volumechange:"jPlayer_volumechange"};c.jPlayer.htmlEvent=["loadstart","abort","emptied","stalled","loadedmetadata","loadeddata","canplaythrough","ratechange"];c.jPlayer.pause=
18 | function(){c.each(c.jPlayer.prototype.instances,function(a,b){b.data("jPlayer").status.srcSet&&b.jPlayer("pause")})};c.jPlayer.timeFormat={showHour:false,showMin:true,showSec:true,padHour:false,padMin:true,padSec:true,sepHour:":",sepMin:":",sepSec:""};c.jPlayer.convertTime=function(a){a=new Date(a*1E3);var b=a.getUTCHours(),d=a.getUTCMinutes();a=a.getUTCSeconds();b=c.jPlayer.timeFormat.padHour&&b<10?"0"+b:b;d=c.jPlayer.timeFormat.padMin&&d<10?"0"+d:d;a=c.jPlayer.timeFormat.padSec&&a<10?"0"+a:a;return(c.jPlayer.timeFormat.showHour?
19 | b+c.jPlayer.timeFormat.sepHour:"")+(c.jPlayer.timeFormat.showMin?d+c.jPlayer.timeFormat.sepMin:"")+(c.jPlayer.timeFormat.showSec?a+c.jPlayer.timeFormat.sepSec:"")};c.jPlayer.uaMatch=function(a){a=a.toLowerCase();var b=/(opera)(?:.*version)?[ \/]([\w.]+)/,d=/(msie) ([\w.]+)/,f=/(mozilla)(?:.*? rv:([\w.]+))?/;a=/(webkit)[ \/]([\w.]+)/.exec(a)||b.exec(a)||d.exec(a)||a.indexOf("compatible")<0&&f.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}};c.jPlayer.browser={};var m=c.jPlayer.uaMatch(navigator.userAgent);
20 | if(m.browser){c.jPlayer.browser[m.browser]=true;c.jPlayer.browser.version=m.version}c.jPlayer.prototype={count:0,version:{script:"2.0.0",needFlash:"2.0.0",flash:"unknown"},options:{swfPath:"js",solution:"html, flash",supplied:"mp3",preload:"metadata",volume:0.8,muted:false,backgroundColor:"#000000",cssSelectorAncestor:"#jp_interface_1",cssSelector:{videoPlay:".jp-video-play",play:".jp-play",pause:".jp-pause",stop:".jp-stop",seekBar:".jp-seek-bar",playBar:".jp-play-bar",mute:".jp-mute",unmute:".jp-unmute",
21 | volumeBar:".jp-volume-bar",volumeBarValue:".jp-volume-bar-value",currentTime:".jp-current-time",duration:".jp-duration"},idPrefix:"jp",errorAlerts:false,warningAlerts:false},instances:{},status:{src:"",media:{},paused:true,format:{},formatType:"",waitForPlay:true,waitForLoad:true,srcSet:false,video:false,seekPercent:0,currentPercentRelative:0,currentPercentAbsolute:0,currentTime:0,duration:0},_status:{volume:h,muted:false,width:0,height:0},internal:{ready:false,instance:h,htmlDlyCmdId:h},solution:{html:true,
22 | flash:true},format:{mp3:{codec:'audio/mpeg; codecs="mp3"',flashCanPlay:true,media:"audio"},m4a:{codec:'audio/mp4; codecs="mp4a.40.2"',flashCanPlay:true,media:"audio"},oga:{codec:'audio/ogg; codecs="vorbis"',flashCanPlay:false,media:"audio"},wav:{codec:'audio/wav; codecs="1"',flashCanPlay:false,media:"audio"},webma:{codec:'audio/webm; codecs="vorbis"',flashCanPlay:false,media:"audio"},m4v:{codec:'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',flashCanPlay:true,media:"video"},ogv:{codec:'video/ogg; codecs="theora, vorbis"',
23 | flashCanPlay:false,media:"video"},webmv:{codec:'video/webm; codecs="vorbis, vp8"',flashCanPlay:false,media:"video"}},_init:function(){var a=this;this.element.empty();this.status=c.extend({},this.status,this._status);this.internal=c.extend({},this.internal);this.formats=[];this.solutions=[];this.require={};this.htmlElement={};this.html={};this.html.audio={};this.html.video={};this.flash={};this.css={};this.css.cs={};this.css.jq={};this.status.volume=this._limitValue(this.options.volume,0,1);this.status.muted=
24 | this.options.muted;this.status.width=this.element.css("width");this.status.height=this.element.css("height");this.element.css({"background-color":this.options.backgroundColor});c.each(this.options.supplied.toLowerCase().split(","),function(e,g){var i=g.replace(/^\s+|\s+$/g,"");if(a.format[i]){var j=false;c.each(a.formats,function(n,k){if(i===k){j=true;return false}});j||a.formats.push(i)}});c.each(this.options.solution.toLowerCase().split(","),function(e,g){var i=g.replace(/^\s+|\s+$/g,"");if(a.solution[i]){var j=
25 | false;c.each(a.solutions,function(n,k){if(i===k){j=true;return false}});j||a.solutions.push(i)}});this.internal.instance="jp_"+this.count;this.instances[this.internal.instance]=this.element;this.element.attr("id")===""&&this.element.attr("id",this.options.idPrefix+"_jplayer_"+this.count);this.internal.self=c.extend({},{id:this.element.attr("id"),jq:this.element});this.internal.audio=c.extend({},{id:this.options.idPrefix+"_audio_"+this.count,jq:h});this.internal.video=c.extend({},{id:this.options.idPrefix+
26 | "_video_"+this.count,jq:h});this.internal.flash=c.extend({},{id:this.options.idPrefix+"_flash_"+this.count,jq:h,swf:this.options.swfPath+(this.options.swfPath!==""&&this.options.swfPath.slice(-1)!=="/"?"/":"")+"Jplayer.swf"});this.internal.poster=c.extend({},{id:this.options.idPrefix+"_poster_"+this.count,jq:h});c.each(c.jPlayer.event,function(e,g){if(a.options[e]!==h){a.element.bind(g+".jPlayer",a.options[e]);a.options[e]=h}});this.htmlElement.poster=document.createElement("img");this.htmlElement.poster.id=
27 | this.internal.poster.id;this.htmlElement.poster.onload=function(){if(!a.status.video||a.status.waitForPlay)a.internal.poster.jq.show()};this.element.append(this.htmlElement.poster);this.internal.poster.jq=c("#"+this.internal.poster.id);this.internal.poster.jq.css({width:this.status.width,height:this.status.height});this.internal.poster.jq.hide();this.require.audio=false;this.require.video=false;c.each(this.formats,function(e,g){a.require[a.format[g].media]=true});this.html.audio.available=false;if(this.require.audio){this.htmlElement.audio=
28 | document.createElement("audio");this.htmlElement.audio.id=this.internal.audio.id;this.html.audio.available=!!this.htmlElement.audio.canPlayType}this.html.video.available=false;if(this.require.video){this.htmlElement.video=document.createElement("video");this.htmlElement.video.id=this.internal.video.id;this.html.video.available=!!this.htmlElement.video.canPlayType}this.flash.available=this._checkForFlash(10);this.html.canPlay={};this.flash.canPlay={};c.each(this.formats,function(e,g){a.html.canPlay[g]=
29 | a.html[a.format[g].media].available&&""!==a.htmlElement[a.format[g].media].canPlayType(a.format[g].codec);a.flash.canPlay[g]=a.format[g].flashCanPlay&&a.flash.available});this.html.desired=false;this.flash.desired=false;c.each(this.solutions,function(e,g){if(e===0)a[g].desired=true;else{var i=false,j=false;c.each(a.formats,function(n,k){if(a[a.solutions[0]].canPlay[k])if(a.format[k].media==="video")j=true;else i=true});a[g].desired=a.require.audio&&!i||a.require.video&&!j}});this.html.support={};
30 | this.flash.support={};c.each(this.formats,function(e,g){a.html.support[g]=a.html.canPlay[g]&&a.html.desired;a.flash.support[g]=a.flash.canPlay[g]&&a.flash.desired});this.html.used=false;this.flash.used=false;c.each(this.solutions,function(e,g){c.each(a.formats,function(i,j){if(a[g].support[j]){a[g].used=true;return false}})});this.html.used||this.flash.used||this._error({type:c.jPlayer.error.NO_SOLUTION,context:"{solution:'"+this.options.solution+"', supplied:'"+this.options.supplied+"'}",message:c.jPlayer.errorMsg.NO_SOLUTION,
31 | hint:c.jPlayer.errorHint.NO_SOLUTION});this.html.active=false;this.html.audio.gate=false;this.html.video.gate=false;this.flash.active=false;this.flash.gate=false;if(this.flash.used){var b="id="+escape(this.internal.self.id)+"&vol="+this.status.volume+"&muted="+this.status.muted;if(c.browser.msie&&Number(c.browser.version)<=8){var d='";var f=[];f[0]='';f[1]='';f[2]='';f[3]='';f[4]='';b=document.createElement(d);for(d=0;d';this.element.append(f)}this.internal.flash.jq=c("#"+this.internal.flash.id);this.internal.flash.jq.css({width:"0px",
34 | height:"0px"})}if(this.html.used){if(this.html.audio.available){this._addHtmlEventListeners(this.htmlElement.audio,this.html.audio);this.element.append(this.htmlElement.audio);this.internal.audio.jq=c("#"+this.internal.audio.id)}if(this.html.video.available){this._addHtmlEventListeners(this.htmlElement.video,this.html.video);this.element.append(this.htmlElement.video);this.internal.video.jq=c("#"+this.internal.video.id);this.internal.video.jq.css({width:"0px",height:"0px"})}}this.html.used&&!this.flash.used&&
35 | window.setTimeout(function(){a.internal.ready=true;a.version.flash="n/a";a._trigger(c.jPlayer.event.ready)},100);c.each(this.options.cssSelector,function(e,g){a._cssSelector(e,g)});this._updateInterface();this._updateButtons(false);this._updateVolume(this.status.volume);this._updateMute(this.status.muted);this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide();c.jPlayer.prototype.count++},destroy:function(){this._resetStatus();this._updateInterface();this._seeked();this.css.jq.currentTime.length&&
36 | this.css.jq.currentTime.text("");this.css.jq.duration.length&&this.css.jq.duration.text("");this.status.srcSet&&this.pause();c.each(this.css.jq,function(a,b){b.unbind(".jPlayer")});this.element.removeData("jPlayer");this.element.unbind(".jPlayer");this.element.empty();this.instances[this.internal.instance]=h},enable:function(){},disable:function(){},_addHtmlEventListeners:function(a,b){var d=this;a.preload=this.options.preload;a.muted=this.options.muted;a.addEventListener("progress",function(){if(b.gate&&
37 | !d.status.waitForLoad){d._getHtmlStatus(a);d._updateInterface();d._trigger(c.jPlayer.event.progress)}},false);a.addEventListener("timeupdate",function(){if(b.gate&&!d.status.waitForLoad){d._getHtmlStatus(a);d._updateInterface();d._trigger(c.jPlayer.event.timeupdate)}},false);a.addEventListener("durationchange",function(){if(b.gate&&!d.status.waitForLoad){d.status.duration=this.duration;d._getHtmlStatus(a);d._updateInterface();d._trigger(c.jPlayer.event.durationchange)}},false);a.addEventListener("play",
38 | function(){if(b.gate&&!d.status.waitForLoad){d._updateButtons(true);d._trigger(c.jPlayer.event.play)}},false);a.addEventListener("playing",function(){if(b.gate&&!d.status.waitForLoad){d._updateButtons(true);d._seeked();d._trigger(c.jPlayer.event.playing)}},false);a.addEventListener("pause",function(){if(b.gate&&!d.status.waitForLoad){d._updateButtons(false);d._trigger(c.jPlayer.event.pause)}},false);a.addEventListener("waiting",function(){if(b.gate&&!d.status.waitForLoad){d._seeking();d._trigger(c.jPlayer.event.waiting)}},
39 | false);a.addEventListener("canplay",function(){if(b.gate&&!d.status.waitForLoad){a.volume=d._volumeFix(d.status.volume);d._trigger(c.jPlayer.event.canplay)}},false);a.addEventListener("seeking",function(){if(b.gate&&!d.status.waitForLoad){d._seeking();d._trigger(c.jPlayer.event.seeking)}},false);a.addEventListener("seeked",function(){if(b.gate&&!d.status.waitForLoad){d._seeked();d._trigger(c.jPlayer.event.seeked)}},false);a.addEventListener("suspend",function(){if(b.gate&&!d.status.waitForLoad){d._seeked();
40 | d._trigger(c.jPlayer.event.suspend)}},false);a.addEventListener("ended",function(){if(b.gate&&!d.status.waitForLoad){if(!c.jPlayer.browser.webkit)d.htmlElement.media.currentTime=0;d.htmlElement.media.pause();d._updateButtons(false);d._getHtmlStatus(a,true);d._updateInterface();d._trigger(c.jPlayer.event.ended)}},false);a.addEventListener("error",function(){if(b.gate&&!d.status.waitForLoad){d._updateButtons(false);d._seeked();if(d.status.srcSet){d.status.waitForLoad=true;d.status.waitForPlay=true;
41 | d.status.video&&d.internal.video.jq.css({width:"0px",height:"0px"});d._validString(d.status.media.poster)&&d.internal.poster.jq.show();d.css.jq.videoPlay.length&&d.css.jq.videoPlay.show();d._error({type:c.jPlayer.error.URL,context:d.status.src,message:c.jPlayer.errorMsg.URL,hint:c.jPlayer.errorHint.URL})}}},false);c.each(c.jPlayer.htmlEvent,function(f,e){a.addEventListener(this,function(){b.gate&&!d.status.waitForLoad&&d._trigger(c.jPlayer.event[e])},false)})},_getHtmlStatus:function(a,b){var d=0,
42 | f=0,e=0,g=0;d=a.currentTime;f=this.status.duration>0?100*d/this.status.duration:0;if(typeof a.seekable==="object"&&a.seekable.length>0){e=this.status.duration>0?100*a.seekable.end(a.seekable.length-1)/this.status.duration:100;g=100*a.currentTime/a.seekable.end(a.seekable.length-1)}else{e=100;g=f}if(b)f=g=d=0;this.status.seekPercent=e;this.status.currentPercentRelative=g;this.status.currentPercentAbsolute=f;this.status.currentTime=d},_resetStatus:function(){this.status=c.extend({},this.status,c.jPlayer.prototype.status)},
43 | _trigger:function(a,b,d){a=c.Event(a);a.jPlayer={};a.jPlayer.version=c.extend({},this.version);a.jPlayer.status=c.extend(true,{},this.status);a.jPlayer.html=c.extend(true,{},this.html);a.jPlayer.flash=c.extend(true,{},this.flash);if(b)a.jPlayer.error=c.extend({},b);if(d)a.jPlayer.warning=c.extend({},d);this.element.trigger(a)},jPlayerFlashEvent:function(a,b){if(a===c.jPlayer.event.ready&&!this.internal.ready){this.internal.ready=true;this.version.flash=b.version;this.version.needFlash!==this.version.flash&&
44 | this._error({type:c.jPlayer.error.VERSION,context:this.version.flash,message:c.jPlayer.errorMsg.VERSION+this.version.flash,hint:c.jPlayer.errorHint.VERSION});this._trigger(a)}if(this.flash.gate)switch(a){case c.jPlayer.event.progress:this._getFlashStatus(b);this._updateInterface();this._trigger(a);break;case c.jPlayer.event.timeupdate:this._getFlashStatus(b);this._updateInterface();this._trigger(a);break;case c.jPlayer.event.play:this._seeked();this._updateButtons(true);this._trigger(a);break;case c.jPlayer.event.pause:this._updateButtons(false);
45 | this._trigger(a);break;case c.jPlayer.event.ended:this._updateButtons(false);this._trigger(a);break;case c.jPlayer.event.error:this.status.waitForLoad=true;this.status.waitForPlay=true;this.status.video&&this.internal.flash.jq.css({width:"0px",height:"0px"});this._validString(this.status.media.poster)&&this.internal.poster.jq.show();this.css.jq.videoPlay.length&&this.css.jq.videoPlay.show();this.status.video?this._flash_setVideo(this.status.media):this._flash_setAudio(this.status.media);this._error({type:c.jPlayer.error.URL,
46 | context:b.src,message:c.jPlayer.errorMsg.URL,hint:c.jPlayer.errorHint.URL});break;case c.jPlayer.event.seeking:this._seeking();this._trigger(a);break;case c.jPlayer.event.seeked:this._seeked();this._trigger(a);break;default:this._trigger(a)}return false},_getFlashStatus:function(a){this.status.seekPercent=a.seekPercent;this.status.currentPercentRelative=a.currentPercentRelative;this.status.currentPercentAbsolute=a.currentPercentAbsolute;this.status.currentTime=a.currentTime;this.status.duration=a.duration},
47 | _updateButtons:function(a){this.status.paused=!a;if(this.css.jq.play.length&&this.css.jq.pause.length)if(a){this.css.jq.play.hide();this.css.jq.pause.show()}else{this.css.jq.play.show();this.css.jq.pause.hide()}},_updateInterface:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.width(this.status.seekPercent+"%");this.css.jq.playBar.length&&this.css.jq.playBar.width(this.status.currentPercentRelative+"%");this.css.jq.currentTime.length&&this.css.jq.currentTime.text(c.jPlayer.convertTime(this.status.currentTime));
48 | this.css.jq.duration.length&&this.css.jq.duration.text(c.jPlayer.convertTime(this.status.duration))},_seeking:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.addClass("jp-seeking-bg")},_seeked:function(){this.css.jq.seekBar.length&&this.css.jq.seekBar.removeClass("jp-seeking-bg")},setMedia:function(a){var b=this;this._seeked();clearTimeout(this.internal.htmlDlyCmdId);var d=this.html.audio.gate,f=this.html.video.gate,e=false;c.each(this.formats,function(g,i){var j=b.format[i].media==="video";
49 | c.each(b.solutions,function(n,k){if(b[k].support[i]&&b._validString(a[i])){var l=k==="html";if(j)if(l){b.html.audio.gate=false;b.html.video.gate=true;b.flash.gate=false}else{b.html.audio.gate=false;b.html.video.gate=false;b.flash.gate=true}else if(l){b.html.audio.gate=true;b.html.video.gate=false;b.flash.gate=false}else{b.html.audio.gate=false;b.html.video.gate=false;b.flash.gate=true}if(b.flash.active||b.html.active&&b.flash.gate||d===b.html.audio.gate&&f===b.html.video.gate)b.clearMedia();else if(d!==
50 | b.html.audio.gate&&f!==b.html.video.gate){b._html_pause();b.status.video&&b.internal.video.jq.css({width:"0px",height:"0px"});b._resetStatus()}if(j){if(l){b._html_setVideo(a);b.html.active=true;b.flash.active=false}else{b._flash_setVideo(a);b.html.active=false;b.flash.active=true}b.css.jq.videoPlay.length&&b.css.jq.videoPlay.show();b.status.video=true}else{if(l){b._html_setAudio(a);b.html.active=true;b.flash.active=false}else{b._flash_setAudio(a);b.html.active=false;b.flash.active=true}b.css.jq.videoPlay.length&&
51 | b.css.jq.videoPlay.hide();b.status.video=false}e=true;return false}});if(e)return false});if(e){if(this._validString(a.poster))if(this.htmlElement.poster.src!==a.poster)this.htmlElement.poster.src=a.poster;else this.internal.poster.jq.show();else this.internal.poster.jq.hide();this.status.srcSet=true;this.status.media=c.extend({},a);this._updateButtons(false);this._updateInterface()}else{this.status.srcSet&&!this.status.waitForPlay&&this.pause();this.html.audio.gate=false;this.html.video.gate=false;
52 | this.flash.gate=false;this.html.active=false;this.flash.active=false;this._resetStatus();this._updateInterface();this._updateButtons(false);this.internal.poster.jq.hide();this.html.used&&this.require.video&&this.internal.video.jq.css({width:"0px",height:"0px"});this.flash.used&&this.internal.flash.jq.css({width:"0px",height:"0px"});this._error({type:c.jPlayer.error.NO_SUPPORT,context:"{supplied:'"+this.options.supplied+"'}",message:c.jPlayer.errorMsg.NO_SUPPORT,hint:c.jPlayer.errorHint.NO_SUPPORT})}},
53 | clearMedia:function(){this._resetStatus();this._updateButtons(false);this.internal.poster.jq.hide();clearTimeout(this.internal.htmlDlyCmdId);if(this.html.active)this._html_clearMedia();else this.flash.active&&this._flash_clearMedia()},load:function(){if(this.status.srcSet)if(this.html.active)this._html_load();else this.flash.active&&this._flash_load();else this._urlNotSetError("load")},play:function(a){a=typeof a==="number"?a:NaN;if(this.status.srcSet)if(this.html.active)this._html_play(a);else this.flash.active&&
54 | this._flash_play(a);else this._urlNotSetError("play")},videoPlay:function(){this.play()},pause:function(a){a=typeof a==="number"?a:NaN;if(this.status.srcSet)if(this.html.active)this._html_pause(a);else this.flash.active&&this._flash_pause(a);else this._urlNotSetError("pause")},pauseOthers:function(){var a=this;c.each(this.instances,function(b,d){a.element!==d&&d.data("jPlayer").status.srcSet&&d.jPlayer("pause")})},stop:function(){if(this.status.srcSet)if(this.html.active)this._html_pause(0);else this.flash.active&&
55 | this._flash_pause(0);else this._urlNotSetError("stop")},playHead:function(a){a=this._limitValue(a,0,100);if(this.status.srcSet)if(this.html.active)this._html_playHead(a);else this.flash.active&&this._flash_playHead(a);else this._urlNotSetError("playHead")},mute:function(){this.status.muted=true;this.html.used&&this._html_mute(true);this.flash.used&&this._flash_mute(true);this._updateMute(true);this._updateVolume(0);this._trigger(c.jPlayer.event.volumechange)},unmute:function(){this.status.muted=false;
56 | this.html.used&&this._html_mute(false);this.flash.used&&this._flash_mute(false);this._updateMute(false);this._updateVolume(this.status.volume);this._trigger(c.jPlayer.event.volumechange)},_updateMute:function(a){if(this.css.jq.mute.length&&this.css.jq.unmute.length)if(a){this.css.jq.mute.hide();this.css.jq.unmute.show()}else{this.css.jq.mute.show();this.css.jq.unmute.hide()}},volume:function(a){a=this._limitValue(a,0,1);this.status.volume=a;this.html.used&&this._html_volume(a);this.flash.used&&this._flash_volume(a);
57 | this.status.muted||this._updateVolume(a);this._trigger(c.jPlayer.event.volumechange)},volumeBar:function(a){if(!this.status.muted&&this.css.jq.volumeBar){var b=this.css.jq.volumeBar.offset();a=a.pageX-b.left;b=this.css.jq.volumeBar.width();this.volume(a/b)}},volumeBarValue:function(a){this.volumeBar(a)},_updateVolume:function(a){this.css.jq.volumeBarValue.length&&this.css.jq.volumeBarValue.width(a*100+"%")},_volumeFix:function(a){var b=0.0010*Math.random();return a+(a<0.5?b:-b)},_cssSelectorAncestor:function(a,
58 | b){this.options.cssSelectorAncestor=a;b&&c.each(this.options.cssSelector,function(d,f){self._cssSelector(d,f)})},_cssSelector:function(a,b){var d=this;if(typeof b==="string")if(c.jPlayer.prototype.options.cssSelector[a]){this.css.jq[a]&&this.css.jq[a].length&&this.css.jq[a].unbind(".jPlayer");this.options.cssSelector[a]=b;this.css.cs[a]=this.options.cssSelectorAncestor+" "+b;this.css.jq[a]=b?c(this.css.cs[a]):[];this.css.jq[a].length&&this.css.jq[a].bind("click.jPlayer",function(f){d[a](f);c(this).blur();
59 | return false});b&&this.css.jq[a].length!==1&&this._warning({type:c.jPlayer.warning.CSS_SELECTOR_COUNT,context:this.css.cs[a],message:c.jPlayer.warningMsg.CSS_SELECTOR_COUNT+this.css.jq[a].length+" found for "+a+" method.",hint:c.jPlayer.warningHint.CSS_SELECTOR_COUNT})}else this._warning({type:c.jPlayer.warning.CSS_SELECTOR_METHOD,context:a,message:c.jPlayer.warningMsg.CSS_SELECTOR_METHOD,hint:c.jPlayer.warningHint.CSS_SELECTOR_METHOD});else this._warning({type:c.jPlayer.warning.CSS_SELECTOR_STRING,
60 | context:b,message:c.jPlayer.warningMsg.CSS_SELECTOR_STRING,hint:c.jPlayer.warningHint.CSS_SELECTOR_STRING})},seekBar:function(a){if(this.css.jq.seekBar){var b=this.css.jq.seekBar.offset();a=a.pageX-b.left;b=this.css.jq.seekBar.width();this.playHead(100*a/b)}},playBar:function(a){this.seekBar(a)},currentTime:function(){},duration:function(){},option:function(a,b){var d=a;if(arguments.length===0)return c.extend(true,{},this.options);if(typeof a==="string"){var f=a.split(".");if(b===h){for(var e=c.extend(true,
61 | {},this.options),g=0;g=9||this.htmlElement.media.load()}},_html_load:function(){if(this.status.waitForLoad){this.status.waitForLoad=false;this.htmlElement.media.src=this.status.src;
65 | try{this.htmlElement.media.load()}catch(a){}}clearTimeout(this.internal.htmlDlyCmdId)},_html_play:function(a){var b=this;this._html_load();this.htmlElement.media.play();if(!isNaN(a))try{this.htmlElement.media.currentTime=a}catch(d){this.internal.htmlDlyCmdId=setTimeout(function(){b.play(a)},100);return}this._html_checkWaitForPlay()},_html_pause:function(a){var b=this;a>0?this._html_load():clearTimeout(this.internal.htmlDlyCmdId);this.htmlElement.media.pause();if(!isNaN(a))try{this.htmlElement.media.currentTime=
66 | a}catch(d){this.internal.htmlDlyCmdId=setTimeout(function(){b.pause(a)},100);return}a>0&&this._html_checkWaitForPlay()},_html_playHead:function(a){var b=this;this._html_load();try{if(typeof this.htmlElement.media.seekable==="object"&&this.htmlElement.media.seekable.length>0)this.htmlElement.media.currentTime=a*this.htmlElement.media.seekable.end(this.htmlElement.media.seekable.length-1)/100;else if(this.htmlElement.media.duration>0&&!isNaN(this.htmlElement.media.duration))this.htmlElement.media.currentTime=
67 | a*this.htmlElement.media.duration/100;else throw"e";}catch(d){this.internal.htmlDlyCmdId=setTimeout(function(){b.playHead(a)},100);return}this.status.waitForLoad||this._html_checkWaitForPlay()},_html_checkWaitForPlay:function(){if(this.status.waitForPlay){this.status.waitForPlay=false;this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide();if(this.status.video){this.internal.poster.jq.hide();this.internal.video.jq.css({width:this.status.width,height:this.status.height})}}},_html_volume:function(a){if(this.html.audio.available)this.htmlElement.audio.volume=
68 | a;if(this.html.video.available)this.htmlElement.video.volume=a},_html_mute:function(a){if(this.html.audio.available)this.htmlElement.audio.muted=a;if(this.html.video.available)this.htmlElement.video.muted=a},_flash_setAudio:function(a){var b=this;try{c.each(this.formats,function(f,e){if(b.flash.support[e]&&a[e]){switch(e){case "m4a":b._getMovie().fl_setAudio_m4a(a[e]);break;case "mp3":b._getMovie().fl_setAudio_mp3(a[e])}b.status.src=a[e];b.status.format[e]=true;b.status.formatType=e;return false}});
69 | if(this.options.preload==="auto"){this._flash_load();this.status.waitForLoad=false}}catch(d){this._flashError(d)}},_flash_setVideo:function(a){var b=this;try{c.each(this.formats,function(f,e){if(b.flash.support[e]&&a[e]){switch(e){case "m4v":b._getMovie().fl_setVideo_m4v(a[e])}b.status.src=a[e];b.status.format[e]=true;b.status.formatType=e;return false}});if(this.options.preload==="auto"){this._flash_load();this.status.waitForLoad=false}}catch(d){this._flashError(d)}},_flash_clearMedia:function(){this.internal.flash.jq.css({width:"0px",
70 | height:"0px"});try{this._getMovie().fl_clearMedia()}catch(a){this._flashError(a)}},_flash_load:function(){try{this._getMovie().fl_load()}catch(a){this._flashError(a)}this.status.waitForLoad=false},_flash_play:function(a){try{this._getMovie().fl_play(a)}catch(b){this._flashError(b)}this.status.waitForLoad=false;this._flash_checkWaitForPlay()},_flash_pause:function(a){try{this._getMovie().fl_pause(a)}catch(b){this._flashError(b)}if(a>0){this.status.waitForLoad=false;this._flash_checkWaitForPlay()}},
71 | _flash_playHead:function(a){try{this._getMovie().fl_play_head(a)}catch(b){this._flashError(b)}this.status.waitForLoad||this._flash_checkWaitForPlay()},_flash_checkWaitForPlay:function(){if(this.status.waitForPlay){this.status.waitForPlay=false;this.css.jq.videoPlay.length&&this.css.jq.videoPlay.hide();if(this.status.video){this.internal.poster.jq.hide();this.internal.flash.jq.css({width:this.status.width,height:this.status.height})}}},_flash_volume:function(a){try{this._getMovie().fl_volume(a)}catch(b){this._flashError(b)}},
72 | _flash_mute:function(a){try{this._getMovie().fl_mute(a)}catch(b){this._flashError(b)}},_getMovie:function(){return document[this.internal.flash.id]},_checkForFlash:function(a){var b=false,d;if(window.ActiveXObject)try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+a);b=true}catch(f){}else if(navigator.plugins&&navigator.mimeTypes.length>0)if(d=navigator.plugins["Shockwave Flash"])if(navigator.plugins["Shockwave Flash"].description.replace(/.*\s(\d+\.\d+).*/,"$1")>=a)b=true;return c.browser.msie&&
73 | Number(c.browser.version)>=9?false:b},_validString:function(a){return a&&typeof a==="string"},_limitValue:function(a,b,d){return ad?d:a},_urlNotSetError:function(a){this._error({type:c.jPlayer.error.URL_NOT_SET,context:a,message:c.jPlayer.errorMsg.URL_NOT_SET,hint:c.jPlayer.errorHint.URL_NOT_SET})},_flashError:function(a){this._error({type:c.jPlayer.error.FLASH,context:this.internal.flash.swf,message:c.jPlayer.errorMsg.FLASH+a.message,hint:c.jPlayer.errorHint.FLASH})},_error:function(a){this._trigger(c.jPlayer.event.error,
74 | a);if(this.options.errorAlerts)this._alert("Error!"+(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+a.context)},_warning:function(a){this._trigger(c.jPlayer.event.warning,h,a);if(this.options.errorAlerts)this._alert("Warning!"+(a.message?"\n\n"+a.message:"")+(a.hint?"\n\n"+a.hint:"")+"\n\nContext: "+a.context)},_alert:function(a){alert("jPlayer "+this.version.script+" : id='"+this.internal.self.id+"' : "+a)}};c.jPlayer.error={FLASH:"e_flash",NO_SOLUTION:"e_no_solution",NO_SUPPORT:"e_no_support",
75 | URL:"e_url",URL_NOT_SET:"e_url_not_set",VERSION:"e_version"};c.jPlayer.errorMsg={FLASH:"jPlayer's Flash fallback is not configured correctly, or a command was issued before the jPlayer Ready event. Details: ",NO_SOLUTION:"No solution can be found by jPlayer in this browser. Neither HTML nor Flash can be used.",NO_SUPPORT:"It is not possible to play any media format provided in setMedia() on this browser using your current options.",URL:"Media URL could not be loaded.",URL_NOT_SET:"Attempt to issue media playback commands, while no media url is set.",
76 | VERSION:"jPlayer "+c.jPlayer.prototype.version.script+" needs Jplayer.swf version "+c.jPlayer.prototype.version.needFlash+" but found "};c.jPlayer.errorHint={FLASH:"Check your swfPath option and that Jplayer.swf is there.",NO_SOLUTION:"Review the jPlayer options: support and supplied.",NO_SUPPORT:"Video or audio formats defined in the supplied option are missing.",URL:"Check media URL is valid.",URL_NOT_SET:"Use setMedia() to set the media URL.",VERSION:"Update jPlayer files."};c.jPlayer.warning=
77 | {CSS_SELECTOR_COUNT:"e_css_selector_count",CSS_SELECTOR_METHOD:"e_css_selector_method",CSS_SELECTOR_STRING:"e_css_selector_string",OPTION_KEY:"e_option_key"};c.jPlayer.warningMsg={CSS_SELECTOR_COUNT:"The number of methodCssSelectors found did not equal one: ",CSS_SELECTOR_METHOD:"The methodName given in jPlayer('cssSelector') is not a valid jPlayer method.",CSS_SELECTOR_STRING:"The methodCssSelector given in jPlayer('cssSelector') is not a String or is empty.",OPTION_KEY:"The option requested in jPlayer('option') is undefined."};
78 | c.jPlayer.warningHint={CSS_SELECTOR_COUNT:"Check your css selector and the ancestor.",CSS_SELECTOR_METHOD:"Check your method name.",CSS_SELECTOR_STRING:"Check your css selector is a string.",OPTION_KEY:"Check your option name."}})(jQuery);
--------------------------------------------------------------------------------
/scripts/jquery.rotate.js:
--------------------------------------------------------------------------------
1 | /*
2 | * rotate: A jQuery cssHooks adding a cross browser 'rotate' property to $.fn.css() and $.fn.animate()
3 | *
4 | * Limitations:
5 | * - requires jQuery 1.4.3+
6 | * - cannot be used together with jquery.scale.js
7 | *
8 | * Copyright (c) 2010 Louis-Rémi Babé twitter.com/louis_remi
9 | * Licensed under the MIT license.
10 | *
11 | * This saved you an hour of work?
12 | * Send me music http://www.amazon.fr/wishlist/HNTU0468LQON
13 | *
14 | */
15 | (function($) {
16 |
17 | var div = document.createElement('div'),
18 | divStyle = div.style,
19 | support = $.support;
20 |
21 | support.transform =
22 | divStyle.MozTransform === ''? 'MozTransform' :
23 | (divStyle.MsTransform === ''? 'MsTransform' :
24 | (divStyle.WebkitTransform === ''? 'WebkitTransform' :
25 | (divStyle.OTransform === ''? 'OTransform' :
26 | (divStyle.transform === ''? 'transform' :
27 | false))));
28 | support.matrixFilter = !support.transform && divStyle.filter === '';
29 | div = null;
30 |
31 | $.cssNumber.rotate = true;
32 | $.cssHooks.rotate = {
33 | set: function( elem, value ) {
34 | var _support = support,
35 | supportTransform = _support.transform,
36 | cos, sin,
37 | centerOrigin;
38 |
39 | if (typeof value === 'string') {
40 | value = toRadian(value);
41 | }
42 |
43 | $.data( elem, 'transform', {
44 | rotate: value
45 | });
46 |
47 | if (supportTransform) {
48 | elem.style[supportTransform] = 'rotate('+ value +'rad)';
49 |
50 | } else if (_support.matrixFilter) {
51 | cos = Math.cos(value);
52 | sin = Math.sin(value);
53 | elem.style.filter = [
54 | "progid:DXImageTransform.Microsoft.Matrix(",
55 | "M11="+cos+",",
56 | "M12="+(-sin)+",",
57 | "M21="+sin+",",
58 | "M22="+cos+",",
59 | "SizingMethod='auto expand'",
60 | ")"
61 | ].join('');
62 |
63 | // From pbakaus's Transformie http://github.com/pbakaus/transformie
64 | if(centerOrigin = $.rotate.centerOrigin) {
65 | elem.style[centerOrigin == 'margin' ? 'marginLeft' : 'left'] = -(elem.offsetWidth/2) + (elem.clientWidth/2) + "px";
66 | elem.style[centerOrigin == 'margin' ? 'marginTop' : 'top'] = -(elem.offsetHeight/2) + (elem.clientHeight/2) + "px";
67 | }
68 | }
69 | },
70 | get: function( elem, computed ) {
71 | var transform = $.data( elem, 'transform' );
72 | return transform && transform.rotate? transform.rotate : 0;
73 | }
74 | };
75 | $.fx.step.rotate = function( fx ) {
76 | $.cssHooks.rotate.set( fx.elem, fx.now+fx.unit );
77 | };
78 |
79 | function radToDeg( rad ) {
80 | return rad * 180 / Math.PI;
81 | }
82 | function toRadian(value) {
83 | if( ~value.indexOf("deg") ) {
84 | return parseInt(value,10) * (Math.PI * 2 / 360);
85 | } else if ( ~value.indexOf("grad") ) {
86 | return parseInt(value,10) * (Math.PI/200);
87 | }
88 | return parseFloat(value);
89 | }
90 |
91 | $.rotate = {
92 | centerOrigin: 'margin',
93 | radToDeg: radToDeg
94 | };
95 |
96 | })(jQuery);
--------------------------------------------------------------------------------
/scripts/main.js:
--------------------------------------------------------------------------------
1 | var targetOrigin = '*';
2 |
3 | window.onload = function() {
4 | initFolders();
5 |
6 | //createAnchors();
7 | //fixZIndex()
8 | //createCloud();
9 | //addDelayToTags();
10 |
11 | if (document.location.hash == "#xxxie") {
12 | document.body.classList.add("activexxxie");
13 | }
14 |
15 | var demos = document.querySelectorAll("#wall > section > article > article .demo");
16 | for (var i = 0; i < demos.length; i++) {
17 | var d = demos[i];
18 | d.style.marginLeft = (-d.clientWidth / 2) + "px";
19 | }
20 |
21 | window.addEventListener("message", function(e) {
22 | if ("stop_demo" == e.data) {
23 | window.parent.postMessage('finished_exit', targetOrigin);
24 | }
25 | }, true);
26 |
27 | document.body.classList.remove("loading");
28 | window.parent.postMessage('loaded', targetOrigin);
29 | }
30 |
31 | function addDelayToTags() {
32 | var s = document.querySelectorAll("#overview span");
33 | for (var i = 0; i < s.length; i++) {
34 | s[i].style.MozTransitionDelay = (~~(Math.random() * 50))/10 + "s";
35 | }
36 | }
37 |
38 | function fixZIndex() {
39 | var a = document.querySelectorAll("#wall > section > article > article");
40 | for (var i = 0; i < a.length; i++) {
41 | var article = a[i];
42 | (function(article) {
43 | article.addEventListener("mouseover", function() {
44 | article.style.zIndex = 4000;
45 | }, true);
46 | article.addEventListener("mouseout", function(e) {
47 | article.style.zIndex = 3999;
48 | }, true);
49 | })(article);
50 | }
51 | }
52 |
53 | function createAnchors() {
54 | var h1 = document.querySelectorAll('#wall > section > article > h1');
55 | for (var i = 0; i < h1.length; i++) { h1[i].id = h1[i].innerHTML; }
56 | h1 = document.querySelectorAll('#wall > section > article > article > h1');
57 | for (var i = 0; i < h1.length; i++) { h1[i].id = h1[i].innerHTML; }
58 | }
59 |
60 | function initFolders() {
61 | var h1 = document.querySelectorAll("#wall > section > article > h1");
62 |
63 | for (var i = 0; i < h1.length; i++) {
64 | var elt = h1[i];
65 |
66 | (function(elt) {
67 | elt.addEventListener("click", function() {
68 | var p = elt.parentNode;
69 |
70 | if (p.classList.contains("closed")) {
71 | p.classList.remove("closed");
72 | } else {
73 | p.classList.add("closed");
74 | }
75 | }, true);
76 | })(elt);
77 | }
78 | }
79 |
80 | function findPos(e) {
81 | var curleft = curtop = 0;
82 | if (e.offsetParent) {
83 | do {
84 | curleft += e.offsetLeft;
85 | curtop += e.offsetTop;
86 | } while (e = e.offsetParent);
87 | }
88 | return {left: curleft, top: curtop};
89 | }
90 |
91 |
92 | // some specific demos scripts
93 |
94 | // text-shadow demo
95 | window.addEventListener("load", function() {
96 | var div = document.querySelector("#textshadowdemo > div");
97 | var p = document.querySelector("#textshadowdemo > div > p");
98 | var pos = findPos(div);
99 | pos.left += Math.round(div.clientWidth / 2) - 72;
100 | pos.top += Math.round(div.clientHeight / 2) + 500;
101 | div.parentNode.addEventListener("mousemove", function(e) {
102 | var x = (e.clientX - (pos.left - window.scrollX));
103 | var y = (e.clientY - (pos.top - window.scrollY));
104 | x *= -0.1;
105 | y *= -0.1;
106 | p.style.textShadow = x + "px " + y + "px 4px black";
107 |
108 | }, true);
109 | }, true);
110 |
111 |
112 | // Form demo
113 | function submitForm() {
114 | try {
115 | var inputs = document.querySelectorAll("#formdemo input");
116 | var who = inputs[0].value;
117 | var demois = inputs[1].value;
118 | var msg = inputs[2].value;
119 | var xhr = new XMLHttpRequest();
120 | xhr.open("GET", "http://184.106.112.6:9384/yo?WHO=" + who + "&DEMOIS=" + demois + "&MSG=" + msg);
121 | xhr.send();
122 | } catch(e) {}
123 | document.querySelector("#formdemo").className = "submited";
124 | return false;
125 | }
126 |
127 | // Open / Close all sections
128 | function toggleFold() {
129 | var a = document.querySelectorAll(".closed");
130 | if (a.length == 0) {
131 | var a = document.querySelectorAll("#wall > section > article");
132 | for (var i = 0; i < a.length; i++) {
133 | a[i].classList.add("closed");
134 | }
135 | } else {
136 | for (var i = 0; i < a.length; i++) {
137 | a[i].classList.remove("closed");
138 | }
139 | }
140 | }
141 |
142 | function createCloud() {
143 | var Bh1 = document.querySelectorAll('#wall > section > article > h1');
144 | var Mh1 = document.querySelectorAll('#wall > section > article > article > h1');
145 |
146 | var txt = "";
147 |
148 | for (var i = 0; i < Bh1.length; i++) {
149 | txt += 'u\'' + Bh1[i].innerHTML + '\' : 100,\n';
150 | }
151 |
152 | for (var i = 0; i < Mh1.length; i++) {
153 | txt += 'u\'' + Mh1[i].innerHTML + '\' : ' + (20 + Mh1.length - i)+ ',\n';
154 | }
155 |
156 | alert(txt);
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/scripts/orientation.js:
--------------------------------------------------------------------------------
1 | var orientationdemo;
2 |
3 | window.addEventListener("load", function() {
4 | orientationdemo = document.querySelector("#orientationdemo > .demo");
5 | }, true);
6 |
7 | window.addEventListener("MozOrientation", function(e) {
8 | if (!orientationdemo) return;
9 | var angle = (e.x * 90) + "deg";
10 | orientationdemo.style.MozTransform = "rotate(" + angle + ")";
11 | }, true);
12 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | /***** @font-face *****/
2 | @font-face { font-family: bebas; src: local("BebasNeue") url(fonts/BebasNeue.otf);}
3 | @font-face { font-family: ubuntu; src: local("Ubuntu") url(fonts/ubuntu.ttf);}
4 | @font-face { font-family: marketing; src: local("MarketingScript") url(fonts/MarketingScript.ttf);}
5 | @font-face { font-family: megalopolis; src: local("MEgalopolisExtra") url(fonts/MEgalopolisExtra.woff);}
6 |
7 |
8 | /***** general stuff *****/
9 |
10 | body { font-family: ubuntu; }
11 |
12 | #plzwait { display: none; }
13 | body.loading #plzwait {display: block; width: 100%; height: 100%; text-align: center; padding-top: 200px;}
14 | body.loading #wall {opacity: 0;}
15 |
16 | h1, h2, h3, h4 { font-family: bebas; }
17 | * {padding: 0px; margin: 0px;}
18 | body { background-color: #343838; }
19 | html { box-shadow: inset 0px 0px 20px black; }
20 |
21 | #wall { background-color: #E1E6E9; width: 900px; padding: 20px; margin: auto; margin-top: 10px; box-shadow: 0px 0px 5px black;}
22 |
23 | #wall > h1 {font-size: 90px; width: 500px; vertical-align: middle; font-weight: normal; text-align: center; margin: auto; margin-top: 30px; text-align: center; position: relative;}
24 | #wall > h1 > span {font-size: 30px; position: absolute; bottom: -2px; right: 48px; color: #999;}
25 |
26 | #shortcredit a { color: #555; }
27 | #shortcredit { opacity: 0.5; top: -150px; right: 0px; font-size: 10px; color: #777; position: relative; width: 100%; text-align: right; }
28 | #shortcredit:hover {opacity: 1;}
29 |
30 | #longcredits a { color: black; }
31 | #longcredits {
32 | color: #555;
33 | }
34 |
35 | /***** tag board *****/
36 |
37 | #overview { margin: 5px; position: relative; background-color: #343838; box-shadow: inset 0px 0px 20px black; height: 320px; border-radius: 10px; margin-left: -5px; margin-right: -5px; }
38 |
39 | .tag {font-size: 18px; transition-duration: 1s; -webkit-transition-duration: 1s; -moz-transition-duration: 1s; cursor: default;}
40 | .tag.big {font-size: 50px;}
41 | .tag { margin-top: 10px; margin-left: 15px; font-family: bebas; position: absolute; text-decoration: none; }
42 | .tag.c0{color: #005f6b;}
43 | .tag.c0:hover {color: #00a2b7;}
44 | .tag.c1{color: #008c9e;}
45 | .tag.c1:hover {color: #00cfea;}
46 | .tag.c2{color: #00dffc;}
47 | .tag.c2:hover {color: #00e1ff;}
48 | .tag.c3{color: #00b4cc;}
49 | .tag.c3:hover {color: #00e1ff;}
50 |
51 | /**********************/
52 |
53 | /* Title */
54 | #wall > section > h1 { font-size: 100px; line-height: 100px; color: #2EC4DD; font-weight: normal; border-top: 2px solid black; padding-top: 20px; }
55 | #wall > section:nth-of-type(2) > h1 { margin-top: 40px; border-top: none; }
56 | #wall > section > article > h1:after { content: "▾"; margin-left: 25px; font-size: 50px; vertical-align: middle; -moz-transition-duration: 1s; -moz-transform: rotate(0deg); -webkit-transition-duration: 1s; -webkit-transform: rotate(0deg); transition-duration: 1s; transform: rotate(0deg); }
57 | #wall > section > article > h1 { font-size: 80px; height: 80px; font-weight: normal; background-image: url(imgs/dashed.png); background-repeat: repeat-x; background-position: left bottom; cursor: pointer; padding-bottom: 10px; -moz-transition: text-indent 0.1s; -webkit-transition: text-indent 0.1s; transition: text-indent 0.1s; }
58 | #wall > section > article > h1:hover { text-indent: 5px; }
59 | #wall > section > article > article > h1 { font-size: 32px; line-height: 32px; letter-spacing: 0px; vertical-align: bottom; font-weight: normal; position: absolute; bottom: 200px; }
60 |
61 |
62 | #wall > section > article { border-top: 10px solid #28C2DA; }
63 | #wall > section > article { line-height: 0px; }
64 | #wall > section > article * { line-height: normal; }
65 | #wall > section > article > article {transition-duration: 1s; -webkit-transition-duration: 1s; -moz-transition-duration: 1s; font-size: 12px; border-top: 0px solid #777; border-bottom: 1px solid #777; width: 225px; display: inline-block; margin-top: 10px; margin-bottom: 10px; padding-top: 10px; padding-bottom: 10px; margin-left: 6px; margin-right: 6px; height: 250px; vertical-align: middle; position: relative; padding-left: 30px; padding-right: 30px; }
66 |
67 | #wall > section > article.closed > h1:after { -moz-transform: rotate(-90deg); -webkit-transform: rotate(-90deg); transform: rotate(-90deg); }
68 |
69 | #wall > section > article.closed > article { height: 0px; border: none; margin-top: 0px; margin-bottom: 0px; padding-top: 0px; padding-bottom: 0px; }
70 |
71 | #wall > section > article > article { overflow: hidden;}
72 |
73 | #wall > section > article > article > p { line-height: 16px; margin-top: 65px; text-align: justify; position: relative; z-index: 41;}
74 |
75 | .demo {
76 | position: absolute;
77 | top: 400px;
78 | left: 50%;
79 | margin-left: -120px;
80 | background-color: white;
81 | border: 5px solid #28C2DA;
82 | z-index: 42;
83 | box-shadow: 0 0 30px black;
84 | -moz-transition-duration: 1s;
85 | -moz-transition-timing-function: cubic-bezier(0.05, 1.4, 0.25, 1);
86 |
87 | -webkit-transition-duration: 1s;
88 | -webkit-transition-timing-function: cubic-bezier(0.05, 1.4, 0.25, 1);
89 |
90 | transition-duration: 1s;
91 | transition-timing-function: cubic-bezier(0.05, 1.4, 0.25, 1);
92 | }
93 |
94 | article:hover > .demo {
95 | top: 100px;
96 | }
97 |
98 | article:hover > .demo.close {
99 | top: 400px;
100 | }
101 |
102 | .activexxxie .xxxie {
103 | opacity: 0.4;
104 | -moz-transform: scale(0.7);
105 | -webkit-transform: scale(0.7);
106 | transform: scale(0.7);
107 | }
108 |
109 | .activexxxie #overview .xxxie {
110 | opacity: 1;
111 | -moz-transform: scale(0)!important;
112 | -webkit-transform: scale(0)!important;
113 | transform: scale(0)!important;
114 | }
115 |
116 | #wall > section > article > article > a {
117 | position: absolute;
118 | z-index: 44;
119 | bottom: -30px; left: 0;
120 | -moz-transition-duration: 0.3s;
121 | -webkit-transition-duration: 0.3s;
122 | transition-duration: 0.3s;
123 | background-color: #28C2DA;
124 | line-height: 20px;
125 | text-align: center;
126 | color: white;
127 | width: 100%;
128 | font-weight: bold;
129 | box-shadow: 0px 0px 20px black;
130 | }
131 |
132 | #wall > section > article > article:hover > a { bottom: 0px; }
133 |
134 | article > .demo > * {
135 | display: block;
136 | }
137 |
138 | #wall > section > article > .experimental:before {
139 | vertical-align: bottom;
140 | content: url(imgs/phial.svg);
141 | position: absolute;
142 | top: 37px; left: 0px;
143 | background-color: #343838;
144 | height: 23px;
145 | border-radius: 5px;
146 | opacity: 0.5;
147 | }
148 |
149 | /*
150 | #wall > section > article > .hasademo:after {
151 | vertical-align: bottom;
152 | content: "D";
153 | font-size: 20px;
154 | font-weight: bold;
155 | padding-left: 5px;
156 | color: white;
157 | position: absolute;
158 | top: 67px; left: 0px;
159 | background-color: #343838;
160 | height: 23px;
161 | border-radius: 5px;
162 | width: 20px;
163 | opacity: 0.5;
164 | }
165 |
166 | #wall > section > article > .hasademo:not(.experimental):after {
167 | top: 38px;
168 | }
169 | */
170 |
171 | .demo .closebutton {
172 | position: absolute;
173 | top: -18px;
174 | right: -18px;
175 | cursor: pointer;
176 | }
177 |
178 | @media all and (max-width: 900px) { #wall { width: 600px; } #overview {display: none;}}
179 | @media all and (max-width: 600px) { #wall { width: 300px; } #wall > section > h1 { font-size: 70px; } }
180 |
181 | /* Mozilla Badge position override */
182 | a#gobackbutton, a#gobackbutton:hover { top: 100px; }
183 |
--------------------------------------------------------------------------------
/webgl_assets/glUtils.js:
--------------------------------------------------------------------------------
1 | // augment Sylvester some
2 | Matrix.Translation = function (v)
3 | {
4 | if (v.elements.length == 2) {
5 | var r = Matrix.I(3);
6 | r.elements[2][0] = v.elements[0];
7 | r.elements[2][1] = v.elements[1];
8 | return r;
9 | }
10 |
11 | if (v.elements.length == 3) {
12 | var r = Matrix.I(4);
13 | r.elements[0][3] = v.elements[0];
14 | r.elements[1][3] = v.elements[1];
15 | r.elements[2][3] = v.elements[2];
16 | return r;
17 | }
18 |
19 | throw "Invalid length for Translation";
20 | }
21 |
22 | Matrix.prototype.flatten = function ()
23 | {
24 | var result = [];
25 | if (this.elements.length == 0)
26 | return [];
27 |
28 |
29 | for (var j = 0; j < this.elements[0].length; j++)
30 | for (var i = 0; i < this.elements.length; i++)
31 | result.push(this.elements[i][j]);
32 | return result;
33 | }
34 |
35 | Matrix.prototype.ensure4x4 = function()
36 | {
37 | if (this.elements.length == 4 &&
38 | this.elements[0].length == 4)
39 | return this;
40 |
41 | if (this.elements.length > 4 ||
42 | this.elements[0].length > 4)
43 | return null;
44 |
45 | for (var i = 0; i < this.elements.length; i++) {
46 | for (var j = this.elements[i].length; j < 4; j++) {
47 | if (i == j)
48 | this.elements[i].push(1);
49 | else
50 | this.elements[i].push(0);
51 | }
52 | }
53 |
54 | for (var i = this.elements.length; i < 4; i++) {
55 | if (i == 0)
56 | this.elements.push([1, 0, 0, 0]);
57 | else if (i == 1)
58 | this.elements.push([0, 1, 0, 0]);
59 | else if (i == 2)
60 | this.elements.push([0, 0, 1, 0]);
61 | else if (i == 3)
62 | this.elements.push([0, 0, 0, 1]);
63 | }
64 |
65 | return this;
66 | };
67 |
68 | Matrix.prototype.make3x3 = function()
69 | {
70 | if (this.elements.length != 4 ||
71 | this.elements[0].length != 4)
72 | return null;
73 |
74 | return Matrix.create([[this.elements[0][0], this.elements[0][1], this.elements[0][2]],
75 | [this.elements[1][0], this.elements[1][1], this.elements[1][2]],
76 | [this.elements[2][0], this.elements[2][1], this.elements[2][2]]]);
77 | };
78 |
79 | Vector.prototype.flatten = function ()
80 | {
81 | return this.elements;
82 | };
83 |
84 | function mht(m) {
85 | var s = "";
86 | if (m.length == 16) {
87 | for (var i = 0; i < 4; i++) {
88 | s += "[" + m[i*4+0].toFixed(4) + "," + m[i*4+1].toFixed(4) + "," + m[i*4+2].toFixed(4) + "," + m[i*4+3].toFixed(4) + "]
";
89 | }
90 | } else if (m.length == 9) {
91 | for (var i = 0; i < 3; i++) {
92 | s += "[" + m[i*3+0].toFixed(4) + "," + m[i*3+1].toFixed(4) + "," + m[i*3+2].toFixed(4) + "]
";
93 | }
94 | } else {
95 | return m.toString();
96 | }
97 | return s;
98 | }
99 |
100 | //
101 | // gluLookAt
102 | //
103 | function makeLookAt(ex, ey, ez,
104 | cx, cy, cz,
105 | ux, uy, uz)
106 | {
107 | var eye = $V([ex, ey, ez]);
108 | var center = $V([cx, cy, cz]);
109 | var up = $V([ux, uy, uz]);
110 |
111 | var mag;
112 |
113 | var z = eye.subtract(center).toUnitVector();
114 | var x = up.cross(z).toUnitVector();
115 | var y = z.cross(x).toUnitVector();
116 |
117 | var m = $M([[x.e(1), x.e(2), x.e(3), 0],
118 | [y.e(1), y.e(2), y.e(3), 0],
119 | [z.e(1), z.e(2), z.e(3), 0],
120 | [0, 0, 0, 1]]);
121 |
122 | var t = $M([[1, 0, 0, -ex],
123 | [0, 1, 0, -ey],
124 | [0, 0, 1, -ez],
125 | [0, 0, 0, 1]]);
126 | return m.x(t);
127 | }
128 |
129 | //
130 | // gluPerspective
131 | //
132 | function makePerspective(fovy, aspect, znear, zfar)
133 | {
134 | var ymax = znear * Math.tan(fovy * Math.PI / 360.0);
135 | var ymin = -ymax;
136 | var xmin = ymin * aspect;
137 | var xmax = ymax * aspect;
138 |
139 | return makeFrustum(xmin, xmax, ymin, ymax, znear, zfar);
140 | }
141 |
142 | //
143 | // glFrustum
144 | //
145 | function makeFrustum(left, right,
146 | bottom, top,
147 | znear, zfar)
148 | {
149 | var X = 2*znear/(right-left);
150 | var Y = 2*znear/(top-bottom);
151 | var A = (right+left)/(right-left);
152 | var B = (top+bottom)/(top-bottom);
153 | var C = -(zfar+znear)/(zfar-znear);
154 | var D = -2*zfar*znear/(zfar-znear);
155 |
156 | return $M([[X, 0, A, 0],
157 | [0, Y, B, 0],
158 | [0, 0, C, D],
159 | [0, 0, -1, 0]]);
160 | }
161 |
162 | //
163 | // glOrtho
164 | //
165 | function makeOrtho(left, right, bottom, top, znear, zfar)
166 | {
167 | var tx = - (right + left) / (right - left);
168 | var ty = - (top + bottom) / (top - bottom);
169 | var tz = - (zfar + znear) / (zfar - znear);
170 |
171 | return $M([[2 / (right - left), 0, 0, tx],
172 | [0, 2 / (top - bottom), 0, ty],
173 | [0, 0, -2 / (zfar - znear), tz],
174 | [0, 0, 0, 1]]);
175 | }
176 |
--------------------------------------------------------------------------------
/webgl_assets/gldemo.js:
--------------------------------------------------------------------------------
1 | var per_fragment_lighting_fs = [
2 | " #ifdef GL_ES",
3 | " precision highp float;",
4 | " #endif",
5 | " varying vec2 vTextureCoord;",
6 | " varying vec4 vTransformedNormal;",
7 | " varying vec4 vPosition;",
8 | " uniform float uMaterialShininess;",
9 | " uniform bool uShowSpecularHighlights;",
10 | " uniform bool uUseLighting;",
11 | " uniform bool uUseTextures;",
12 | " uniform vec3 uAmbientColor;",
13 | " uniform vec3 uPointLightingLocation;",
14 | " uniform vec3 uPointLightingSpecularColor;",
15 | " uniform vec3 uPointLightingDiffuseColor;",
16 | " uniform sampler2D uSampler;",
17 | " void main(void) {",
18 | " vec3 lightWeighting;",
19 | " if (!uUseLighting) {",
20 | " lightWeighting = vec3(1.0, 1.0, 1.0);",
21 | " } else {",
22 | " vec3 lightDirection = normalize(uPointLightingLocation - vPosition.xyz);",
23 | " vec3 normal = normalize(vTransformedNormal.xyz);",
24 | " float specularLightWeighting = 0.0;",
25 | " if (uShowSpecularHighlights) {",
26 | " vec3 eyeDirection = normalize(-vPosition.xyz);",
27 | " vec3 reflectionDirection = reflect(-lightDirection, normal);",
28 | " specularLightWeighting = pow(max(dot(reflectionDirection, eyeDirection), 0.0), uMaterialShininess);",
29 | " }",
30 | " float diffuseLightWeighting = max(dot(normal, lightDirection), 0.0);",
31 | " lightWeighting = uAmbientColor",
32 | " + uPointLightingSpecularColor * specularLightWeighting",
33 | " + uPointLightingDiffuseColor * diffuseLightWeighting;",
34 | " }",
35 | " vec4 fragmentColor;",
36 | " if (uUseTextures) {",
37 | " fragmentColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));",
38 | " } else {",
39 | " fragmentColor = vec4(1.0, 1.0, 1.0, 1.0);",
40 | " }",
41 | " gl_FragColor = vec4(fragmentColor.rgb * lightWeighting, fragmentColor.a);",
42 | " }"
43 | ].join("\n");
44 |
45 | var per_fragment_lighting_vs = [
46 | " attribute vec3 aVertexPosition;",
47 | " attribute vec3 aVertexNormal;",
48 | " attribute vec2 aTextureCoord;",
49 | " uniform mat4 uMVMatrix;",
50 | " uniform mat4 uPMatrix;",
51 | " uniform mat4 uNMatrix;",
52 | " varying vec2 vTextureCoord;",
53 | " varying vec4 vTransformedNormal;",
54 | " varying vec4 vPosition;",
55 | " void main(void) {",
56 | " vPosition = uMVMatrix * vec4(aVertexPosition, 1.0);",
57 | " gl_Position = uPMatrix * vPosition;",
58 | " vTextureCoord = aTextureCoord;",
59 | " vTransformedNormal = uNMatrix * vec4(aVertexNormal, 1.0);",
60 | " }",
61 | ].join("\n");
62 |
63 |
64 |
65 |
66 | var gl;
67 |
68 | var nogl;
69 |
70 | function initGL(canvas) {
71 | try {
72 | gl = canvas.getContext("experimental-webgl");
73 | gl.viewportWidth = canvas.width;
74 | gl.viewportHeight = canvas.height;
75 | nogl = false;
76 | } catch(e) {}
77 | if (!gl) {
78 | nogl = true;
79 | document.body.classList.add("nogl");
80 | }
81 | }
82 |
83 |
84 | function getShader(gl, str, isFragment) {
85 | var shader;
86 | if (isFragment) {
87 | shader = gl.createShader(gl.FRAGMENT_SHADER);
88 | } else {
89 | shader = gl.createShader(gl.VERTEX_SHADER);
90 | }
91 |
92 | gl.shaderSource(shader, str);
93 | gl.compileShader(shader);
94 |
95 | if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
96 | alert(gl.getShaderInfoLog(shader));
97 | return null;
98 | }
99 |
100 | return shader;
101 | }
102 |
103 |
104 | var shaderProgram;
105 | function initShaders() {
106 | var fragmentShader = getShader(gl, per_fragment_lighting_fs, true);
107 | var vertexShader = getShader(gl, per_fragment_lighting_vs, false);
108 |
109 | shaderProgram = gl.createProgram();
110 | gl.attachShader(shaderProgram, vertexShader);
111 | gl.attachShader(shaderProgram, fragmentShader);
112 | gl.linkProgram(shaderProgram);
113 |
114 | if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
115 | alert("Could not initialise shaders");
116 | }
117 |
118 | gl.useProgram(shaderProgram);
119 |
120 | shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
121 | gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
122 |
123 | shaderProgram.vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
124 | gl.enableVertexAttribArray(shaderProgram.vertexNormalAttribute);
125 |
126 | shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
127 | gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
128 |
129 | shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
130 | shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
131 | shaderProgram.nMatrixUniform = gl.getUniformLocation(shaderProgram, "uNMatrix");
132 | shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
133 | shaderProgram.materialShininessUniform = gl.getUniformLocation(shaderProgram, "uMaterialShininess");
134 | shaderProgram.showSpecularHighlightsUniform = gl.getUniformLocation(shaderProgram, "uShowSpecularHighlights");
135 | shaderProgram.useTexturesUniform = gl.getUniformLocation(shaderProgram, "uUseTextures");
136 | shaderProgram.useLightingUniform = gl.getUniformLocation(shaderProgram, "uUseLighting");
137 | shaderProgram.ambientColorUniform = gl.getUniformLocation(shaderProgram, "uAmbientColor");
138 | shaderProgram.pointLightingLocationUniform = gl.getUniformLocation(shaderProgram, "uPointLightingLocation");
139 | shaderProgram.pointLightingSpecularColorUniform = gl.getUniformLocation(shaderProgram, "uPointLightingSpecularColor");
140 | shaderProgram.pointLightingDiffuseColorUniform = gl.getUniformLocation(shaderProgram, "uPointLightingDiffuseColor");
141 | }
142 |
143 |
144 | function handleLoadedTexture(texture) {
145 | gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
146 | gl.bindTexture(gl.TEXTURE_2D, texture);
147 | gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image);
148 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
149 | gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
150 | gl.generateMipmap(gl.TEXTURE_2D);
151 |
152 | gl.bindTexture(gl.TEXTURE_2D, null);
153 | tick();
154 | }
155 |
156 |
157 | var earthTexture;
158 | var galvanizedTexture;
159 | function initTextures() {
160 | earthTexture = gl.createTexture();
161 | earthTexture.image = new Image();
162 | earthTexture.image.onload = function() {
163 | handleLoadedTexture(earthTexture)
164 | }
165 | earthTexture.image.src = "earth.jpg";
166 |
167 | galvanizedTexture = gl.createTexture();
168 | galvanizedTexture.image = new Image();
169 | galvanizedTexture.image.onload = function() {
170 | handleLoadedTexture(galvanizedTexture)
171 | }
172 | galvanizedTexture.image.src = "webgl_assets/texture.jpg";
173 | }
174 |
175 |
176 | var mvMatrix;
177 | var mvMatrixStack = [];
178 |
179 | function mvPushMatrix(m) {
180 | if (m) {
181 | mvMatrixStack.push(m.dup());
182 | mvMatrix = m.dup();
183 | } else {
184 | mvMatrixStack.push(mvMatrix.dup());
185 | }
186 | }
187 |
188 | function mvPopMatrix() {
189 | if (mvMatrixStack.length == 0) {
190 | throw "Invalid popMatrix!";
191 | }
192 | mvMatrix = mvMatrixStack.pop();
193 | return mvMatrix;
194 | }
195 |
196 | function loadIdentity() {
197 | mvMatrix = Matrix.I(4);
198 | }
199 |
200 |
201 | function multMatrix(m) {
202 | mvMatrix = mvMatrix.x(m);
203 | }
204 |
205 |
206 | function mvTranslate(v) {
207 | var m = Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4();
208 | multMatrix(m);
209 | }
210 |
211 |
212 | function createRotationMatrix(angle, v) {
213 | var arad = angle * Math.PI / 180.0;
214 | return Matrix.Rotation(arad, $V([v[0], v[1], v[2]])).ensure4x4();
215 | }
216 |
217 |
218 | function mvRotate(angle, v) {
219 | multMatrix(createRotationMatrix(angle, v));
220 | }
221 |
222 |
223 | var pMatrix;
224 | function perspective(fovy, aspect, znear, zfar) {
225 | pMatrix = makePerspective(fovy, aspect, znear, zfar);
226 | }
227 |
228 |
229 | function setMatrixUniforms() {
230 | gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, new Float32Array(pMatrix.flatten()));
231 | gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, new Float32Array(mvMatrix.flatten()));
232 |
233 | var normalMatrix = mvMatrix.inverse();
234 | normalMatrix = normalMatrix.transpose();
235 | gl.uniformMatrix4fv(shaderProgram.nMatrixUniform, false, new Float32Array(normalMatrix.flatten()));
236 | }
237 |
238 |
239 | var teapotVertexPositionBuffer;
240 | var teapotVertexNormalBuffer;
241 | var teapotVertexTextureCoordBuffer;
242 | var teapotVertexIndexBuffer;
243 | function handleLoadedTeapot(teapotData) {
244 | teapotVertexNormalBuffer = gl.createBuffer();
245 | gl.bindBuffer(gl.ARRAY_BUFFER, teapotVertexNormalBuffer);
246 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(teapotData.vertexNormals), gl.STATIC_DRAW);
247 | teapotVertexNormalBuffer.itemSize = 3;
248 | teapotVertexNormalBuffer.numItems = teapotData.vertexNormals.length / 3;
249 |
250 | teapotVertexTextureCoordBuffer = gl.createBuffer();
251 | gl.bindBuffer(gl.ARRAY_BUFFER, teapotVertexTextureCoordBuffer);
252 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(teapotData.vertexTextureCoords), gl.STATIC_DRAW);
253 | teapotVertexTextureCoordBuffer.itemSize = 2;
254 | teapotVertexTextureCoordBuffer.numItems = teapotData.vertexTextureCoords.length / 2;
255 |
256 | teapotVertexPositionBuffer = gl.createBuffer();
257 | gl.bindBuffer(gl.ARRAY_BUFFER, teapotVertexPositionBuffer);
258 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(teapotData.vertexPositions), gl.STATIC_DRAW);
259 | teapotVertexPositionBuffer.itemSize = 3;
260 | teapotVertexPositionBuffer.numItems = teapotData.vertexPositions.length / 3;
261 |
262 | teapotVertexIndexBuffer = gl.createBuffer();
263 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, teapotVertexIndexBuffer);
264 | gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(teapotData.indices), gl.STREAM_DRAW);
265 | teapotVertexIndexBuffer.itemSize = 1;
266 | teapotVertexIndexBuffer.numItems = teapotData.indices.length;
267 | }
268 |
269 |
270 | function loadTeapot() {
271 | var request = new XMLHttpRequest();
272 | request.open("GET", "webgl_assets/Teapot.json");
273 | request.onreadystatechange = function() {
274 | if (request.readyState == 4) {
275 | handleLoadedTeapot(JSON.parse(request.responseText));
276 | }
277 | }
278 | request.send();
279 | }
280 |
281 |
282 | var teapotAngle = 180;
283 |
284 | function drawScene() {
285 | gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
286 | gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
287 |
288 | if (teapotVertexPositionBuffer == null || teapotVertexNormalBuffer == null || teapotVertexTextureCoordBuffer == null || teapotVertexIndexBuffer == null) {
289 | return;
290 | }
291 |
292 | perspective(50, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
293 |
294 | var specularHighlights = true;
295 | gl.uniform1i(shaderProgram.showSpecularHighlightsUniform, specularHighlights);
296 |
297 | var lighting = true;
298 | gl.uniform1i(shaderProgram.useLightingUniform, lighting);
299 | if (lighting) {
300 | gl.uniform3f(shaderProgram.ambientColorUniform, 0.2, 0.2, 0.2);
301 | gl.uniform3f(shaderProgram.pointLightingLocationUniform, -10, 4, -20);
302 | gl.uniform3f(shaderProgram.pointLightingSpecularColorUniform, 0.8, 0.8, 0.8);
303 | gl.uniform3f(shaderProgram.pointLightingDiffuseColorUniform, 0.8, 0.8, 0.8);
304 | }
305 |
306 | var texture = "galvanized";
307 | gl.uniform1i(shaderProgram.useTexturesUniform, texture != "none");
308 |
309 | loadIdentity();
310 |
311 | mvTranslate([0, 0, -30]);
312 | mvRotate(23.4, [1, 0, -1]);
313 | mvRotate(teapotAngle, [0, 1, 0]);
314 | gl.activeTexture(gl.TEXTURE0);
315 | if (texture == "earth") {
316 | gl.bindTexture(gl.TEXTURE_2D, earthTexture);
317 | } else if (texture == "galvanized") {
318 | gl.bindTexture(gl.TEXTURE_2D, galvanizedTexture);
319 | }
320 | gl.uniform1i(shaderProgram.samplerUniform, 0);
321 |
322 | gl.uniform1f(shaderProgram.materialShininessUniform, 12);
323 |
324 | gl.bindBuffer(gl.ARRAY_BUFFER, teapotVertexPositionBuffer);
325 | gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, teapotVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
326 |
327 | gl.bindBuffer(gl.ARRAY_BUFFER, teapotVertexTextureCoordBuffer);
328 | gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, teapotVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
329 |
330 | gl.bindBuffer(gl.ARRAY_BUFFER, teapotVertexNormalBuffer);
331 | gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute, teapotVertexNormalBuffer.itemSize, gl.FLOAT, false, 0, 0);
332 |
333 | gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, teapotVertexIndexBuffer);
334 | setMatrixUniforms();
335 | gl.drawElements(gl.TRIANGLES, teapotVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
336 | }
337 |
338 |
339 |
340 | var teapotRotating = false;
341 |
342 | function tick() {
343 | drawScene();
344 | teapotAngle += 1.5;
345 | if (teapotRotating) setTimeout(tick, 60);
346 | }
347 |
348 |
349 | function webGLStart() {
350 | var canvas = document.querySelector("#webgldemo canvas");
351 | initGL(canvas);
352 | initShaders();
353 | initTextures();
354 | loadTeapot();
355 |
356 | gl.clearColor(0.0, 0.0, 0.0, 0.0);
357 |
358 | gl.clearDepth(1.0);
359 |
360 | gl.enable(gl.DEPTH_TEST);
361 | gl.depthFunc(gl.LEQUAL);
362 | tick();
363 | }
364 |
365 | window.addEventListener("load", webGLStart, true);
366 |
367 | function startTeaPot() {
368 | if (nogl) return;
369 | teapotRotating = true; tick();
370 | }
371 | function stopTeaPot() {
372 | if (nogl) return;
373 | teapotRotating = false;
374 | }
375 |
--------------------------------------------------------------------------------
/webgl_assets/sylvester.js:
--------------------------------------------------------------------------------
1 | eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('9 17={3i:\'0.1.3\',16:1e-6};l v(){}v.23={e:l(i){8(i<1||i>7.4.q)?w:7.4[i-1]},2R:l(){8 7.4.q},1u:l(){8 F.1x(7.2u(7))},24:l(a){9 n=7.4.q;9 V=a.4||a;o(n!=V.q){8 1L}J{o(F.13(7.4[n-1]-V[n-1])>17.16){8 1L}}H(--n);8 2x},1q:l(){8 v.u(7.4)},1b:l(a){9 b=[];7.28(l(x,i){b.19(a(x,i))});8 v.u(b)},28:l(a){9 n=7.4.q,k=n,i;J{i=k-n;a(7.4[i],i+1)}H(--n)},2q:l(){9 r=7.1u();o(r===0){8 7.1q()}8 7.1b(l(x){8 x/r})},1C:l(a){9 V=a.4||a;9 n=7.4.q,k=n,i;o(n!=V.q){8 w}9 b=0,1D=0,1F=0;7.28(l(x,i){b+=x*V[i-1];1D+=x*x;1F+=V[i-1]*V[i-1]});1D=F.1x(1D);1F=F.1x(1F);o(1D*1F===0){8 w}9 c=b/(1D*1F);o(c<-1){c=-1}o(c>1){c=1}8 F.37(c)},1m:l(a){9 b=7.1C(a);8(b===w)?w:(b<=17.16)},34:l(a){9 b=7.1C(a);8(b===w)?w:(F.13(b-F.1A)<=17.16)},2k:l(a){9 b=7.2u(a);8(b===w)?w:(F.13(b)<=17.16)},2j:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x+V[i-1]})},2C:l(a){9 V=a.4||a;o(7.4.q!=V.q){8 w}8 7.1b(l(x,i){8 x-V[i-1]})},22:l(k){8 7.1b(l(x){8 x*k})},x:l(k){8 7.22(k)},2u:l(a){9 V=a.4||a;9 i,2g=0,n=7.4.q;o(n!=V.q){8 w}J{2g+=7.4[n-1]*V[n-1]}H(--n);8 2g},2f:l(a){9 B=a.4||a;o(7.4.q!=3||B.q!=3){8 w}9 A=7.4;8 v.u([(A[1]*B[2])-(A[2]*B[1]),(A[2]*B[0])-(A[0]*B[2]),(A[0]*B[1])-(A[1]*B[0])])},2A:l(){9 m=0,n=7.4.q,k=n,i;J{i=k-n;o(F.13(7.4[i])>F.13(m)){m=7.4[i]}}H(--n);8 m},2Z:l(x){9 a=w,n=7.4.q,k=n,i;J{i=k-n;o(a===w&&7.4[i]==x){a=i+1}}H(--n);8 a},3g:l(){8 S.2X(7.4)},2d:l(){8 7.1b(l(x){8 F.2d(x)})},2V:l(x){8 7.1b(l(y){8(F.13(y-x)<=17.16)?x:y})},1o:l(a){o(a.K){8 a.1o(7)}9 V=a.4||a;o(V.q!=7.4.q){8 w}9 b=0,2b;7.28(l(x,i){2b=x-V[i-1];b+=2b*2b});8 F.1x(b)},3a:l(a){8 a.1h(7)},2T:l(a){8 a.1h(7)},1V:l(t,a){9 V,R,x,y,z;2S(7.4.q){27 2:V=a.4||a;o(V.q!=2){8 w}R=S.1R(t).4;x=7.4[0]-V[0];y=7.4[1]-V[1];8 v.u([V[0]+R[0][0]*x+R[0][1]*y,V[1]+R[1][0]*x+R[1][1]*y]);1I;27 3:o(!a.U){8 w}9 C=a.1r(7).4;R=S.1R(t,a.U).4;x=7.4[0]-C[0];y=7.4[1]-C[1];z=7.4[2]-C[2];8 v.u([C[0]+R[0][0]*x+R[0][1]*y+R[0][2]*z,C[1]+R[1][0]*x+R[1][1]*y+R[1][2]*z,C[2]+R[2][0]*x+R[2][1]*y+R[2][2]*z]);1I;2P:8 w}},1t:l(a){o(a.K){9 P=7.4.2O();9 C=a.1r(P).4;8 v.u([C[0]+(C[0]-P[0]),C[1]+(C[1]-P[1]),C[2]+(C[2]-(P[2]||0))])}1d{9 Q=a.4||a;o(7.4.q!=Q.q){8 w}8 7.1b(l(x,i){8 Q[i-1]+(Q[i-1]-x)})}},1N:l(){9 V=7.1q();2S(V.4.q){27 3:1I;27 2:V.4.19(0);1I;2P:8 w}8 V},2n:l(){8\'[\'+7.4.2K(\', \')+\']\'},26:l(a){7.4=(a.4||a).2O();8 7}};v.u=l(a){9 V=25 v();8 V.26(a)};v.i=v.u([1,0,0]);v.j=v.u([0,1,0]);v.k=v.u([0,0,1]);v.2J=l(n){9 a=[];J{a.19(F.2F())}H(--n);8 v.u(a)};v.1j=l(n){9 a=[];J{a.19(0)}H(--n);8 v.u(a)};l S(){}S.23={e:l(i,j){o(i<1||i>7.4.q||j<1||j>7.4[0].q){8 w}8 7.4[i-1][j-1]},33:l(i){o(i>7.4.q){8 w}8 v.u(7.4[i-1])},2E:l(j){o(j>7.4[0].q){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][j-1])}H(--n);8 v.u(a)},2R:l(){8{2D:7.4.q,1p:7.4[0].q}},2D:l(){8 7.4.q},1p:l(){8 7.4[0].q},24:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(7.4.q!=M.q||7.4[0].q!=M[0].q){8 1L}9 b=7.4.q,15=b,i,G,10=7.4[0].q,j;J{i=15-b;G=10;J{j=10-G;o(F.13(7.4[i][j]-M[i][j])>17.16){8 1L}}H(--G)}H(--b);8 2x},1q:l(){8 S.u(7.4)},1b:l(a){9 b=[],12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;b[i]=[];J{j=10-G;b[i][j]=a(7.4[i][j],i+1,j+1)}H(--G)}H(--12);8 S.u(b)},2i:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4.q==M.q&&7.4[0].q==M[0].q)},2j:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x+M[i-1][j-1]})},2C:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2i(M)){8 w}8 7.1b(l(x,i,j){8 x-M[i-1][j-1]})},2B:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}8(7.4[0].q==M.q)},22:l(a){o(!a.4){8 7.1b(l(x){8 x*a})}9 b=a.1u?2x:1L;9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}o(!7.2B(M)){8 w}9 d=7.4.q,15=d,i,G,10=M[0].q,j;9 e=7.4[0].q,4=[],21,20,c;J{i=15-d;4[i]=[];G=10;J{j=10-G;21=0;20=e;J{c=e-20;21+=7.4[i][c]*M[c][j]}H(--20);4[i][j]=21}H(--G)}H(--d);9 M=S.u(4);8 b?M.2E(1):M},x:l(a){8 7.22(a)},32:l(a,b,c,d){9 e=[],12=c,i,G,j;9 f=7.4.q,1p=7.4[0].q;J{i=c-12;e[i]=[];G=d;J{j=d-G;e[i][j]=7.4[(a+i-1)%f][(b+j-1)%1p]}H(--G)}H(--12);8 S.u(e)},31:l(){9 a=7.4.q,1p=7.4[0].q;9 b=[],12=1p,i,G,j;J{i=1p-12;b[i]=[];G=a;J{j=a-G;b[i][j]=7.4[j][i]}H(--G)}H(--12);8 S.u(b)},1y:l(){8(7.4.q==7.4[0].q)},2A:l(){9 m=0,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(F.13(7.4[i][j])>F.13(m)){m=7.4[i][j]}}H(--G)}H(--12);8 m},2Z:l(x){9 a=w,12=7.4.q,15=12,i,G,10=7.4[0].q,j;J{i=15-12;G=10;J{j=10-G;o(7.4[i][j]==x){8{i:i+1,j:j+1}}}H(--G)}H(--12);8 w},30:l(){o(!7.1y){8 w}9 a=[],n=7.4.q,k=n,i;J{i=k-n;a.19(7.4[i][i])}H(--n);8 v.u(a)},1K:l(){9 M=7.1q(),1c;9 n=7.4.q,k=n,i,1s,1n=7.4[0].q,p;J{i=k-n;o(M.4[i][i]==0){2e(j=i+1;j17.16){1Y++;1I}}H(--G)}H(--a);8 1Y},3d:l(){8 7.1Y()},2W:l(a){9 M=a.4||a;o(1g(M[0][0])==\'1f\'){M=S.u(M).4}9 T=7.1q(),1p=T.4[0].q;9 b=T.4.q,15=b,i,G,10=M[0].q,j;o(b!=M.q){8 w}J{i=15-b;G=10;J{j=10-G;T.4[i][1p+j]=M[i][j]}H(--G)}H(--b);8 T},2w:l(){o(!7.1y()||7.2y()){8 w}9 a=7.4.q,15=a,i,j;9 M=7.2W(S.I(a)).1K();9 b,1n=M.4[0].q,p,1c,2v;9 c=[],2c;J{i=a-1;1c=[];b=1n;c[i]=[];2v=M.4[i][i];J{p=1n-b;2c=M.4[i][p]/2v;1c.19(2c);o(p>=15){c[i].19(2c)}}H(--b);M.4[i]=1c;2e(j=0;j3||b.4.q>3){8 w}9 c=b.1u();o(c===0){8 w}7.K=a;7.U=v.u([b.4[0]/c,b.4[1]/c,b.4[2]/c]);8 7}};14.u=l(a,b){9 L=25 14();8 L.1Z(a,b)};14.X=14.u(v.1j(3),v.i);14.Y=14.u(v.1j(3),v.j);14.Z=14.u(v.1j(3),v.k);l 11(){}11.23={24:l(a){8(7.1h(a.K)&&7.1m(a))},1q:l(){8 11.u(7.K,7.W)},2U:l(a){9 V=a.4||a;8 11.u([7.K.4[0]+V[0],7.K.4[1]+V[1],7.K.4[2]+(V[2]||0)],7.W)},1m:l(a){9 b;o(a.W){b=7.W.1C(a.W);8(F.13(b)<=17.16||F.13(F.1A-b)<=17.16)}1d o(a.U){8 7.W.2k(a.U)}8 w},2k:l(a){9 b=7.W.1C(a.W);8(F.13(F.1A/2-b)<=17.16)},1o:l(a){o(7.1v(a)||7.1h(a)){8 0}o(a.K){9 A=7.K.4,B=a.K.4,N=7.W.4;8 F.13((A[0]-B[0])*N[0]+(A[1]-B[1])*N[1]+(A[2]-B[2])*N[2])}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;8 F.13((A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2])}},1h:l(a){o(a.W){8 w}o(a.U){8(7.1h(a.K)&&7.1h(a.K.2j(a.U)))}1d{9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=F.13(N[0]*(A[0]-P[0])+N[1]*(A[1]-P[1])+N[2]*(A[2]-(P[2]||0)));8(b<=17.16)}},1v:l(a){o(1g(a.U)==\'1f\'&&1g(a.W)==\'1f\'){8 w}8!7.1m(a)},1U:l(a){o(!7.1v(a)){8 w}o(a.U){9 A=a.K.4,D=a.U.4,P=7.K.4,N=7.W.4;9 b=(N[0]*(P[0]-A[0])+N[1]*(P[1]-A[1])+N[2]*(P[2]-A[2]))/(N[0]*D[0]+N[1]*D[1]+N[2]*D[2]);8 v.u([A[0]+D[0]*b,A[1]+D[1]*b,A[2]+D[2]*b])}1d o(a.W){9 c=7.W.2f(a.W).2q();9 N=7.W.4,A=7.K.4,O=a.W.4,B=a.K.4;9 d=S.1j(2,2),i=0;H(d.2y()){i++;d=S.u([[N[i%3],N[(i+1)%3]],[O[i%3],O[(i+1)%3]]])}9 e=d.2w().4;9 x=N[0]*A[0]+N[1]*A[1]+N[2]*A[2];9 y=O[0]*B[0]+O[1]*B[1]+O[2]*B[2];9 f=[e[0][0]*x+e[0][1]*y,e[1][0]*x+e[1][1]*y];9 g=[];2e(9 j=1;j<=3;j++){g.19((i==j)?0:f[(j+(5-i)%3)%3])}8 14.u(g,c)}},1r:l(a){9 P=a.4||a;9 A=7.K.4,N=7.W.4;9 b=(A[0]-P[0])*N[0]+(A[1]-P[1])*N[1]+(A[2]-(P[2]||0))*N[2];8 v.u([P[0]+N[0]*b,P[1]+N[1]*b,(P[2]||0)+N[2]*b])},1V:l(t,a){9 R=S.1R(t,a.U).4;9 C=a.1r(7.K).4;9 A=7.K.4,N=7.W.4;9 b=C[0],1E=C[1],1J=C[2],1w=A[0],18=A[1],1a=A[2];9 x=1w-b,y=18-1E,z=1a-1J;8 11.u([b+R[0][0]*x+R[0][1]*y+R[0][2]*z,1E+R[1][0]*x+R[1][1]*y+R[1][2]*z,1J+R[2][0]*x+R[2][1]*y+R[2][2]*z],[R[0][0]*N[0]+R[0][1]*N[1]+R[0][2]*N[2],R[1][0]*N[0]+R[1][1]*N[1]+R[1][2]*N[2],R[2][0]*N[0]+R[2][1]*N[1]+R[2][2]*N[2]])},1t:l(a){o(a.W){9 A=7.K.4,N=7.W.4;9 b=A[0],18=A[1],1a=A[2],2M=N[0],2L=N[1],2Q=N[2];9 c=7.K.1t(a).4;9 d=b+2M,2p=18+2L,2m=1a+2Q;9 Q=a.1r([d,2p,2m]).4;9 e=[Q[0]+(Q[0]-d)-c[0],Q[1]+(Q[1]-2p)-c[1],Q[2]+(Q[2]-2m)-c[2]];8 11.u(c,e)}1d o(a.U){8 7.1V(F.1A,a)}1d{9 P=a.4||a;8 11.u(7.K.1t([P[0],P[1],(P[2]||0)]),7.W)}},1Z:l(a,b,c){a=v.u(a);a=a.1N();o(a===w){8 w}b=v.u(b);b=b.1N();o(b===w){8 w}o(1g(c)==\'1f\'){c=w}1d{c=v.u(c);c=c.1N();o(c===w){8 w}}9 d=a.4[0],18=a.4[1],1a=a.4[2];9 e=b.4[0],1W=b.4[1],1X=b.4[2];9 f,1i;o(c!==w){9 g=c.4[0],2l=c.4[1],2t=c.4[2];f=v.u([(1W-18)*(2t-1a)-(1X-1a)*(2l-18),(1X-1a)*(g-d)-(e-d)*(2t-1a),(e-d)*(2l-18)-(1W-18)*(g-d)]);1i=f.1u();o(1i===0){8 w}f=v.u([f.4[0]/1i,f.4[1]/1i,f.4[2]/1i])}1d{1i=F.1x(e*e+1W*1W+1X*1X);o(1i===0){8 w}f=v.u([b.4[0]/1i,b.4[1]/1i,b.4[2]/1i])}7.K=a;7.W=f;8 7}};11.u=l(a,b,c){9 P=25 11();8 P.1Z(a,b,c)};11.2I=11.u(v.1j(3),v.k);11.2H=11.u(v.1j(3),v.i);11.2G=11.u(v.1j(3),v.j);11.36=11.2I;11.35=11.2H;11.3j=11.2G;9 $V=v.u;9 $M=S.u;9 $L=14.u;9 $P=11.u;',62,206,'||||elements|||this|return|var||||||||||||function|||if||length||||create|Vector|null|||||||||Math|nj|while||do|anchor||||||||Matrix||direction||normal||||kj|Plane|ni|abs|Line|ki|precision|Sylvester|A2|push|A3|map|els|else||undefined|typeof|contains|mod|Zero|D3|D2|isParallelTo|kp|distanceFrom|cols|dup|pointClosestTo|np|reflectionIn|modulus|intersects|A1|sqrt|isSquare|X2|PI|X3|angleFrom|mod1|C2|mod2|sin|cos|break|C3|toRightTriangular|false|Y3|to3D|E2|E1|E3|Rotation|Y2|Y1|intersectionWith|rotate|v12|v13|rank|setVectors|nc|sum|multiply|prototype|eql|new|setElements|case|each|PA3|PA2|part|new_element|round|for|cross|product|AD2|isSameSizeAs|add|isPerpendicularTo|v22|AN3|inspect|AD3|AN2|toUnitVector|PsubQ3|PsubQ2|v23|dot|divisor|inverse|true|isSingular|determinant|max|canMultiplyFromLeft|subtract|rows|col|random|ZX|YZ|XY|Random|join|N2|N1|D1|slice|default|N3|dimensions|switch|liesIn|translate|snapTo|augment|Diagonal|trace|indexOf|diagonal|transpose|minor|row|isAntiparallelTo|ZY|YX|acos|RotationZ|RotationY|liesOn|RotationX|inv|rk|tr|det|toDiagonalMatrix|toUpperTriangular|version|XZ'.split('|'),0,{}))
--------------------------------------------------------------------------------
/webgl_assets/texture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/paulrouget/html5dashboard/6fe0865bf493597bb3b788fce712c3a9d051ebcb/webgl_assets/texture.jpg
--------------------------------------------------------------------------------