diff --git a/synthesis/index.html b/synthesis/index.html new file mode 100644 index 0000000..99d7c0c --- /dev/null +++ b/synthesis/index.html @@ -0,0 +1,17 @@ + + + + http micro tempo + + + + + + + + + + + + + \ No newline at end of file diff --git a/synthesis/lib/hhhh.js b/synthesis/lib/hhhh.js new file mode 100644 index 0000000..d482065 --- /dev/null +++ b/synthesis/lib/hhhh.js @@ -0,0 +1,55 @@ + +var modfactor = 750.0; +var modfactor_gain = 10750.0; + +function create_none_synth() { + var s = new FMSynth('triangle', 100, 'saw', 2, 300); + s.add_filter(new LowPassFilter()); + s.update = function(val) { + this.modulator_freq(val / modfactor); + }; + return s; +} + +function create_ad_synth() { + var s = new SimpleOscillator('square', 100); + s.add_filter(new NoiseConvolver()); + s.update = function(val) { + this.modulator_freq(val / 25); + }; + return s; +} + +function create_tracker_synth() { + var s = new PinkNoiseGenerator(); + //s.add_filter(new NoiseConvolver()); + s.update = function(val) { + this.modulator_gain(val / modfactor_gain); + }; + return s; +} + +function create_analytics_synth() { + var s = new WhiteNoiseGenerator(); + //s.add_filter(new DistortionShaper(55)); + s.update = function(val) { + this.modulator_gain(val / modfactor_gain); + }; + return s; +} + +function create_widget_synth() { + var s = new PinkNoiseGenerator(); + s.update = function(val) { + this.modulator_gain(val / modfactor_gain); + }; + return s; +} + +function create_privacy_synth() { + var s = new WhiteNoiseGenerator(); + s.update = function(val) { + this.modulator_gain(val / modfactor_gain); + }; + return s; +} diff --git a/synthesis/lib/nnnn.js b/synthesis/lib/nnnn.js new file mode 100644 index 0000000..b058204 --- /dev/null +++ b/synthesis/lib/nnnn.js @@ -0,0 +1,60 @@ +var refresh_rate_ms = 4; +var bb; + +function draw(url) { + + if(/csv$/.test(url)) { + url = url + '.svg'; + } else { + return; + } + + d3.xml(url, function(xml) { + svg_node = document.importNode(xml.documentElement, true); + svg = d3.select('#track'); + svg.style('width', svg_node.width.baseVal.value); + svg.style('height', svg_node.height.baseVal.value); + svg.node().appendChild(svg_node); + + d3.select(svg_node) + .attr('id', 'svg_track'); + + // + var g = d3.select(svg_node).append('g'); + var b = g.append('foreignObject') + .attr('x', '85') + .attr('y', '350') + .attr('width', '100') + .attr('height', '100') + .append('xhtml:body'); + bb = b.append('input') + .attr('type', 'button') + .attr('value', 'synthesise') + .attr('onclick', 'go()'); + + var line = svg.append('svg:line') + .attr('x1', 0) + .attr('y1', 0) + .attr('x2', 0) + .attr('y1', svg_node.height.baseVal.value) + .style('stroke', 'rgb(255,0,0)') + .style('stroke-width', 1); + + window.setInterval( function() { + line.attr('x1', tick_cnt); //var tick_cnt = 0; // from ssss.js + line.attr('x2', tick_cnt); + }, refresh_rate_ms); + + }); +} + +function go() { + if(bb.attr('value') == 'pause') { + bb.attr('value', 'synthesise'); + stop_all_synths(); + } else { + bb.attr('value', 'pause'); + start_all_synths(); + } +} + diff --git a/synthesis/lib/ssss.js b/synthesis/lib/ssss.js new file mode 100644 index 0000000..71c5f48 --- /dev/null +++ b/synthesis/lib/ssss.js @@ -0,0 +1,193 @@ +var data = []; +var start_times_dict = {}; +var end_times_dict = {}; +var start_times = []; +var end_times = []; + +var next_start = 0; +var next_end = 0; + +var processing_data = []; + +// timer parameters +var tick_cnt = 0; /// this is passed to the drawing +var time_incr_ms = 2; +var time_end = 0; +var interval_id = 0; + +var p = true; + +var params = { + "-" : {'bytes': 0, 'synth': null, 'active': 0}, + "ad" : {'bytes': 0, 'synth': null, 'active': 0}, + "tracker" : {'bytes': 0, 'synth': null, 'active': 0}, + "analytics" : {'bytes': 0, 'synth': null, 'active': 0}, + "widget" : {'bytes': 0, 'synth': null, 'active': 0}, + "privacy" : {'bytes': 0, 'synth': null, 'active': 0} +}; + +function synthesise(csv_input_file_url) { + + $.ajax({ + type: 'GET', + url: csv_input_file_url, + dataType: 'text', + success: function(resp) { + data = $.csv.toObjects(resp); + start_times = {}; + end_times = {}; + + for(var i = 0; i < data.length; i++) { + + var start = +data[i]['Start Time (ms)']; + var end = +data[i]['End Time (ms)']; + var size = +data[i]['Object Size']; + + if(!(start in start_times_dict)) { + start_times_dict[start] = []; + } + start_times_dict[start].push(i); + + if(!(end in end_times_dict)) { + end_times_dict[end] = []; + } + end_times_dict[end].push(i); + + data[i].incr = linear_increment(start, end, size); + data[i].incr_tick = 0; + + if(end > time_end) time_end = end; + } + + $('#end').html(time_end); + + start_times = Object.keys(start_times_dict); + end_times = Object.keys(end_times_dict); + + start_times.sort(function(a, b){ + return a - b; + }); + end_times.sort(function(a, b) { + return a - b; + }); + + // create synths + + params['-'].synth = create_none_synth(); + params['ad'].synth = create_ad_synth(); + params['tracker'].synth = create_tracker_synth(); + params['analytics'].synth = create_analytics_synth(); + params['widget'].synth = create_widget_synth(); + params['privacy'].synth = create_privacy_synth(); + + stop_all_synths(); + + interval_id = window.setInterval(tick, time_incr_ms); + + }, + error: function(xhr, status, error) { + console.log("error loading -- " + csv_input_file); + } + }); +} + +function linear_increment(start_ms, end_ms, size_bytes) { + return size_bytes / (end_ms - start_ms); +} + +function start_all_synths() { + p = false; + params['-'].synth.start(); + params['ad'].synth.start(); + params['tracker'].synth.start(); + params['analytics'].synth.start(); + params['widget'].synth.start(); + params['privacy'].synth.start(); +} + +function stop_all_synths() { + p = true; + params['-'].synth.stop(); + params['ad'].synth.stop(); + params['tracker'].synth.stop(); + params['analytics'].synth.stop(); + params['widget'].synth.stop(); + params['privacy'].synth.stop(); +} + + +function tick() { + + if(p) return; + + $('#time').html(tick_cnt); + if(tick_cnt >= time_end + 1) { + window.clearInterval(interval_id); + stop_all_synths(); + } else if(tick_cnt == 0) { + start_all_synths(); + } + + if(start_times[next_start] == tick_cnt) { + var start_indices = start_times_dict[tick_cnt]; + processing_data = processing_data.concat(start_indices) + for(var i = 0; i < start_indices.length; i++) { + var d = data[start_indices[i]] + params[d.bug_type].active = params[d.bug_type].active + 1; + } + next_start++; + } + if(end_times[next_end] == tick_cnt) { + + var end_indices = end_times_dict[tick_cnt]; + for(var i = 0; i < end_indices.length; i++) { + var processing_indx = processing_data.indexOf(end_indices[i]); + if(processing_indx != -1) { + var d = data[end_indices[i]] + processing_data.splice(processing_indx, 1); + params[d.bug_type].bytes -= parseInt(d['Object Size']); + params[d.bug_type].active = params[d.bug_type].active - 1; + } else { + console.log('not proccesed -- ' + end_indices[i]); + } + } + + next_end++; + } + + for(var i = 0; i < processing_data.length; i++) { + var d = data[processing_data[i]]; + params[d.bug_type].bytes += d.incr; + d.incr_tick = d.incr_tick + 1; + } + + params['-'].synth.update(params['-'].bytes); + params['ad'].synth.update(params['ad'].bytes); + params['tracker'].synth.update(params['tracker'].bytes); + params['analytics'].synth.update(params['analytics'].bytes); + params['widget'].synth.update(params['widget'].bytes); + params['privacy'].synth.update(params['privacy'].bytes); + + // $('#none').html(params['-'].active); + // $('#none_bytes').html(Math.ceil(params['-'].bytes)); + + // $('#ad').html(params['ad'].active); + // $('#ad_bytes').html(Math.ceil(params['ad'].bytes)); + + // $('#tracker').html(params['tracker'].active); + // $('#tracker_bytes').html(Math.ceil(params['tracker'].bytes)); + + // $('#analytics').html(params['analytics'].active); + // $('#analytics_bytes').html(Math.ceil(params['analytics'].bytes)); + + // $('#widget').html(params['widget'].active); + // $('#widget_bytes').html(Math.ceil(params['widget'].bytes)); + + // $('#privacy').html(params['privacy'].active); + // $('#privacy_bytes').html(Math.ceil(params['privacy'].bytes)); + + + tick_cnt++; + +} + diff --git a/synthesis/lib/tttt.js b/synthesis/lib/tttt.js new file mode 100644 index 0000000..577df6d --- /dev/null +++ b/synthesis/lib/tttt.js @@ -0,0 +1,20 @@ + +var svg_repo_url = "http://gauthiier.github.io/www-micro-temporalities/img/scores/"; +var csv_repo_url = "https://raw.githubusercontent.com/gauthiier/www-micro-temporalities/master/webpagetest/filtered/"; + +var data_ref = get_param('ref'); + +if(data_ref === "") { + console.log('no ref aborting...'); +} else { + console.log('ref: ' + data_ref); + draw(svg_repo_url + data_ref); + synthesise(csv_repo_url + data_ref); +} + +function get_param(name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); +} \ No newline at end of file diff --git a/synthesis/lib/yyyy.js b/synthesis/lib/yyyy.js new file mode 100644 index 0000000..ec863d8 --- /dev/null +++ b/synthesis/lib/yyyy.js @@ -0,0 +1,302 @@ +//////////// +//////////////////////////// +//////////// + +var AudioContext = window.AudioContext || window.webkitAudioContext; + +var audioCtx = new AudioContext(); + +function Modulator(waveform, freq, gain) { + // actual modulating freq + this.osc = audioCtx.createOscillator(); + this.osc.type = waveform; + this.osc.frequency.value = freq; + // not sure about this -- but the gain is what modulates + this.gain = audioCtx.createGain(); + this.gain.gain.value = gain; + // connect + this.osc.connect(this.gain); +} + +function Carrier(waveform, freq) { + this.osc = audioCtx.createOscillator(); + this.osc.type = waveform; + this.osc.frequency.value = freq; + this.gain = audioCtx.createGain(); + this.osc.connect(this.gain); +} + +function FMSynth(waveform_c, freq_c, waveform_m, freq_m, gain_m) { + + this.carrier = new Carrier(waveform_c, freq_c); + this.modulator = new Modulator(waveform_m, freq_m, gain_m); + + this.bitcrusher_filter = new BitCrusherFilter(); + + this.modulator.gain.connect(this.carrier.osc.frequency); + this.carrier.gain.connect(audioCtx.destination); + + this.started = false; + + this.start = function() { + if(!this.started) { + this.carrier.osc.start(); + this.modulator.osc.start(); + this.started = true; + } else { + this.carrier.gain.gain.value = 1.0; + } + } + + this.stop = function() { + this.carrier.gain.gain.value = 0.0; + } + + this.modulator_freq_incr = function(incr) { + this.modulator.osc.frequency.value = this.modulator.osc.frequency.value + incr; + } + + this.modulator_freq = function(freq) { + this.modulator.osc.frequency.value = freq; + } + + this.add_filter = function (filter) { + this.filter = filter; + this.carrier.osc.disconnect(this.carrier.gain); + this.carrier.osc.connect(this.filter); + this.filter.connect(this.carrier.gain); + } + +} + +function SimpleOscillator(waveform, freq) { + + this.oscillator = new Carrier(waveform, freq); + this.oscillator.gain.connect(audioCtx.destination); + + this.started = false; + + this.start = function() { + if(!this.started) { + this.oscillator.osc.start(); + this.started = true; + } else { + this.oscillator.gain.gain.value = 1.0; + } + } + + this.stop = function() { + this.oscillator.gain.gain.value = 0.0; + } + + this.modulator_freq_incr = function(incr) { + this.oscillator.osc.frequency.value = this.modulator.osc.frequency.value + incr; + } + + this.modulator_freq = function(freq) { + this.oscillator.osc.frequency.value = freq; + } + + this.add_filter = function (filter) { + this.filter = filter; + this.oscillator.osc.disconnect(this.oscillator.gain); + this.oscillator.osc.connect(this.filter); + this.filter.connect(this.oscillator.gain); + } + + +} + +function WhiteNoiseGenerator() { + + // generates 2 sec noise buffer + var bufferSize = audioCtx.sampleRate * 2; + var noiseBuffer = audioCtx.createBuffer(1, bufferSize, audioCtx.sampleRate); + var out = noiseBuffer.getChannelData(0); + for(var i = 0; i < bufferSize; i++) { + out[i] = Math.random() * 2 - 1; + } + + this.whitenoise = audioCtx.createBufferSource(); + this.whitenoise.buffer = noiseBuffer; + this.whitenoise.loop = true; + + this.gain = audioCtx.createGain(); + this.whitenoise.connect(this.gain); + this.gain.connect(audioCtx.destination); + + this.started = false; + + this.start = function() { + if(!this.started) + this.whitenoise.start(0); + this.started = true; + } + + this.stop = function() { + this.gain.gain.value = 0.0; + this.started = false; + } + + this.modulator_gain_incr = function(incr) { + this.gain.gain.value = this.gain.gain.value + incr; + } + + this.modulator_gain = function(gain) { + this.gain.gain.value = gain; + } + + this.add_filter = function(filter) { + this.filter = filter; + this.whitenoise.disconnect(this.gain); + this.whitenoise.connect(this.filter); + this.filter.connect(this.gain); + } + +} + +function PinkNoiseGenerator() { + + var bufferSize = 4096; + this.pinknoise = audioCtx.createScriptProcessor(bufferSize, 1, 1); + var b0, b1, b2, b3, b4, b5, b6; + b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0; + this.pinknoise.onaudioprocess = function(e) { + var out = e.outputBuffer.getChannelData(0); + for(var i = 0; i < bufferSize; i++) { + var white = Math.random() * 2 - 1; + b0 = 0.99886 * b0 + white * 0.0555179; + b1 = 0.99332 * b1 + white * 0.0750759; + b2 = 0.96900 * b2 + white * 0.1538520; + b3 = 0.86650 * b3 + white * 0.3104856; + b4 = 0.55000 * b4 + white * 0.5329522; + b5 = -0.7616 * b5 - white * 0.0168980; + out[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362; + out[i] *= 0.11; // (roughly) compensate for gain + b6 = white * 0.115926; + } + }; + + this.gain = audioCtx.createGain(); + this.pinknoise.connect(this.gain); + this.gain.connect(audioCtx.destination); + + this.started = false; + + this.start = function() { + } + + this.stop = function() { + this.gain.gain.value = 0.0; + this.started = false; + } + + this.modulator_gain_incr = function(incr) { + this.gain.gain.value = this.gain.gain.value + incr; + } + + this.modulator_gain = function(gain) { + this.gain.gain.value = gain; + } + + this.add_filter = function(filter) { + this.filter = filter; + this.pinknoise.disconnect(this.gain); + this.pinknoise.connect(this.filter); + this.filter.connect(this.gain); + } + +} + +//////////// Filters + +function BitCrusherFilter() { + var bufferSize = 4096; + var node = audioCtx.createScriptProcessor(bufferSize, 1, 1); + node.bits = 14; // between 1 and 16 + node.normfreq = 0.1; // between 0.0 and 1.0 + var step = Math.pow(1/2, node.bits); + var phaser = 0; + var last = 0; + node.onaudioprocess = function(e) { + var input = e.inputBuffer.getChannelData(0); + var output = e.outputBuffer.getChannelData(0); + for (var i = 0; i < bufferSize; i++) { + phaser += node.normfreq; + if (phaser >= 1.0) { + phaser -= 1.0; + last = step * Math.floor(input[i] / step + 0.5); + } + output[i] = last; + } + }; + return node; +} + +function LowPassFilter() { + var bufferSize = 4096; + var node = audioCtx.createScriptProcessor(bufferSize, 1, 1); + var prev = 0; + node.onaudioprocess = function(e) { + var input = e.inputBuffer.getChannelData(0); + var out = e.outputBuffer.getChannelData(0); + for (var i = 0; i < bufferSize; i++) { + out[i] = (input[i] + prev) / 2.0; + prev = out[i]; + } + }; + return node; +} + +//////////// Convolvers + +function NoiseConvolver() { + var convolver = audioCtx.createConvolver(); + var noiseBuffer = audioCtx.createBuffer(2, 0.5 * audioCtx.sampleRate, audioCtx.sampleRate); + var left = noiseBuffer.getChannelData(0); + var rigth = noiseBuffer.getChannelData(1); + for(var i = 0; i < noiseBuffer.length; i++) { + left[i] = Math.random() * 2 - 1; + rigth[i] = Math.random() * 2 - 1; + } + convolver.buffer = noiseBuffer; + return convolver; +} + +//////////// WaveShapers + +function DistortionShaper(distortion_val) { + this.waveshaper = audioCtx.createWaveShaper(); + + this.makeDistortionCurve = function(amount) { + var k = typeof amount === 'number' ? amount : 50, + n_samples = 44100, + curve = new Float32Array(n_samples), + deg = Math.PI / 180, + i = 0, + x; + for ( ; i < n_samples; ++i ) { + x = i * 2 / n_samples - 1; + curve[i] = ( 3 + k ) * x * 20 * deg / ( Math.PI + k * Math.abs(x) ); + } + return curve; + } + + this.distortion = function(amount) { + this.waveshaper.curve = this.makeDistortionCurve(amount); + } + + this.waveshaper.curve = this.makeDistortionCurve(distortion_val); + + return this.waveshaper; +} + + + + + + + + + +