Skip to content

Instantly share code, notes, and snippets.

@ameenkhan07
Created November 22, 2016 10:54
Show Gist options
  • Save ameenkhan07/fec7b2828cf6732d8900eba6730f8642 to your computer and use it in GitHub Desktop.
Save ameenkhan07/fec7b2828cf6732d8900eba6730f8642 to your computer and use it in GitHub Desktop.
Github Audio Under the Hood -
var eventQueue = [];
var svg;
var element;
var drawingArea;
var width;
var height;
var volume = 0.6;
var ULTIMATE_DREAM_KILLER = false; // https://github.com/debugger22/github-audio/pull/19
var orgRepoFilterNames = [];
var scale_factor = 6,
note_overlap = 2,
note_timeout = 300,
current_notes = 0,
max_life = 20000;
var svg_background_color_online = '#0288D1',
svg_background_color_offline = '#E91E63',
svg_text_color = '#FFFFFF',
newuser_box_color = 'rgb(41, 128, 185)',
push_color = 'rgb(155, 89, 182)',
issue_color = 'rgb(46, 204, 113)',
pull_request_color = 'rgb(46, 204, 113)',
comment_color = 'rgb(46, 204, 113)',
edit_color = '#fff',
total_sounds = 51;
var celesta = [],
clav = [],
swells = [],
all_loaded = false;
var socket = io();
socket.on('github', function (data) {
$('.online-users-count').html(data.connected_users);
data.data.forEach(function(event){
if(!isEventInQueue(event)){
// Filter out events only specified by the user
if(orgRepoFilterNames != []){
// Don't consider pushes to github.io repos when org filter is on
if(new RegExp(orgRepoFilterNames.join("|")).test(event.repo_name)
&& event.repo_name.indexOf('github.io') == -1){
eventQueue.push(event);
}
}else{
eventQueue.push(event);
}
}
});
// Don't let the eventQueue grow more than 1000
if (eventQueue.length > 1000) eventQueue = eventQueue.slice(0, 1000);
});
socket.on('connect', function(){
if(svg != null){
$('svg').css('background-color', svg_background_color_online);
$('header').css('background-color', svg_background_color_online);
$('.offline-text').css('visibility', 'hidden');
$('.events-remaining-text').css('visibility', 'hidden');
$('.events-remaining-value').css('visibility', 'hidden');
}
});
socket.on('disconnect', function(){
if(svg != null){
$('svg').css('background-color', svg_background_color_offline);
$('header').css('background-color', svg_background_color_offline);
$('.offline-text').css('visibility', 'visible');
$('.events-remaining-text').css('visibility', 'visible');
$('.events-remaining-value').css('visibility', 'visible');
}
});
socket.on('error', function(){
if(svg != null){
$('svg').css('background-color', svg_background_color_offline);
$('header').css('background-color', svg_background_color_offline);
$('.offline-text').css('visibility', 'visible');
$('.events-remaining-text').css('visibility', 'visible');
$('.events-remaining-value').css('visibility', 'visible');
}
});
/**
* This function checks whether an event is already in the queue
*/
function isEventInQueue(event){
for(var i=0; i<eventQueue.length; i++){
if(eventQueue[i].id == event.id)
return true;
}
return false;
}
/**
* This function adds a filter for events that we don't want to hear.
*
* To extend this function, simply add return true for events that should be filtered.
*/
function shouldEventBeIgnored(event){
// This adds an easter egg to only play closed PRs
if (!!ULTIMATE_DREAM_KILLER)
return (event.type !== "PullRequestEvent" || event.action !== "closed");
return false;
}
$(function(){
element = document.documentElement;
drawingArea = document.getElementsByTagName('#area')[0];
width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
height = (window.innerHeight - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
$('svg').css('background-color', svg_background_color_online);
$('header').css('background-color', svg_background_color_online);
$('svg text').css('color', svg_text_color);
$('#volumeSlider').slider({
'max': 100,
'min': 0,
'value': volume*100,
'slide' : function(event, ui){
volume = ui.value/100.0;
Howler.volume(volume);
},
'change' : function(event, ui){
volume = ui.value/100.0;
Howler.volume(volume);
}
});
// Main drawing area
svg = d3.select("#area").append("svg");
svg.attr({width: width, height: height});
svg.style('background-color', svg_background_color_online);
// For window resizes
var update_window = function() {
width = window.innerWidth || element.clientWidth || drawingArea.clientWidth;
height = (window.innerHeight - $('header').height())|| (element.clientHeight - $('header').height()) || (drawingArea.clientHeight - $('header').height());
svg.attr("width", width).attr("height", height);
}
window.onresize = update_window;
update_window();
var loaded_sounds = 0;
var sound_load = function(r) {
loaded_sounds += 1;
if (loaded_sounds == total_sounds) {
all_loaded = true;
setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000));
// Starting the second exchange makes music a bad experience
// setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 2000));
}
}
// Load sounds
for (var i = 1; i <= 24; i++) {
if (i > 9) {
fn = 'c0' + i;
} else {
fn = 'c00' + i;
}
celesta.push(new Howl({
src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.ogg',
'https://d1fz9d31zqor6x.cloudfront.net/sounds/celesta/' + fn + '.mp3'],
volume : 0.7,
onload : sound_load(),
buffer: true,
}))
clav.push(new Howl({
src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.ogg',
'https://d1fz9d31zqor6x.cloudfront.net/sounds/clav/' + fn + '.mp3'],
volume : 0.4,
onload : sound_load(),
buffer: true,
}))
}
for (var i = 1; i <= 3; i++) {
swells.push(new Howl({
src : ['https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.ogg',
'https://d1fz9d31zqor6x.cloudfront.net/sounds/swells/swell' + i + '.mp3'],
volume : 1,
onload : sound_load(),
buffer: true,
}));
}
Howler.volume(volume);
// Make header and footer visible
$('body').css('visibility', 'visible');
$('#org-repo-filter-name').on('input', function() {
orgRepoFilterNames = $('#org-repo-filter-name').val().split(' ');
eventQueue = [];
});
});
/**
* Randomly selects a swell sound and plays it
*/
function playRandomSwell() {
var index = Math.round(Math.random() * (swells.length - 1));
swells[index].play();
}
/**
* Plays a sound(celesta and clav) based on passed parameters
*/
function playSound(size, type) {
var max_pitch = 100.0;
var log_used = 1.0715307808111486871978099;
var pitch = 100 - Math.min(max_pitch, Math.log(size + log_used) / Math.log(log_used));
var index = Math.floor(pitch / 100.0 * Object.keys(celesta).length);
var fuzz = Math.floor(Math.random() * 4) - 2;
index += fuzz;
index = Math.min(Object.keys(celesta).length - 1, index);
index = Math.max(1, index);
if (current_notes < note_overlap) {
current_notes++;
if (type == 'IssuesEvent' || type == 'IssueCommentEvent') {
clav[index].play();
} else if(type == 'PushEvent') {
celesta[index].play();
}else{
playRandomSwell();
}
setTimeout(function() {
current_notes--;
}, note_timeout);
}
}
// Following are the n numbers of event consumers
// consuming n events each per second with a random delay between them
function playFromQueueExchange1(){
var event = eventQueue.shift();
if(event != null && event.message != null && !shouldEventBeIgnored(event) && svg != null){
playSound(event.message.length*1.1, event.type);
if(!document.hidden)
drawEvent(event, svg);
}
setTimeout(playFromQueueExchange1, Math.floor(Math.random() * 1000) + 500);
$('.events-remaining-value').html(eventQueue.length);
}
function playFromQueueExchange2(){
var event = eventQueue.shift();
if(event != null && event.message != null && !shouldEventBeIgnored(event) && svg != null){
playSound(event.message.length, event.type);
if(!document.hidden)
drawEvent(event, svg);
}
setTimeout(playFromQueueExchange2, Math.floor(Math.random() * 800) + 500);
$('.events-remaining-value').html(eventQueue.length);
}
// This method capitalizes the string in place
String.prototype.capitalize=function(all){
if(all){
return this.split(' ').map(function(e){
return e.capitalize().join(' ');
});
}else{
return this.charAt(0).toUpperCase() + this.slice(1);
}
}
function drawEvent(data, svg_area) {
var starting_opacity = 1;
var opacity = 1 / (100 / data.message.length);
if (opacity > 0.5) {
opacity = 0.5;
}
var size = data.message.length;
var label_text;
var ring_radius = 80;
var ring_anim_duration = 3000;
svg_text_color = '#FFFFFF';
switch(data.type){
case "PushEvent":
label_text = data.user.capitalize() + " pushed to " + data.repo_name;
edit_color = '#B2DFDB';
break;
case "PullRequestEvent":
label_text = data.user.capitalize() + " " +
data.action + " " + " a PR for " + data.repo_name;
edit_color = '#C6FF00';
ring_anim_duration = 10000;
ring_radius = 600;
break;
case "IssuesEvent":
label_text = data.user.capitalize() + " " +
data.action + " an issue in " + data.repo_name;
edit_color = '#FFEB3B';
break;
case "IssueCommentEvent":
label_text = data.user.capitalize() + " commented in " + data.repo_name;
edit_color = '#FF5722';
break;
}
var csize = size;
var no_label = false;
var type = data.type;
var circle_id = 'd' + ((Math.random() * 100000) | 0);
var abs_size = Math.abs(size);
size = Math.max(Math.sqrt(abs_size) * scale_factor, 3);
Math.seedrandom(data.message)
var x = Math.random() * (width - size) + size;
var y = Math.random() * (height - size) + size;
var circle_group = svg_area.append('g')
.attr('transform', 'translate(' + x + ', ' + y + ')')
.attr('fill', edit_color)
.style('opacity', starting_opacity)
var ring = circle_group.append('circle');
ring.attr({r: size, stroke: 'none'});
ring.transition()
.attr('r', size + ring_radius)
.style('opacity', 0)
.ease(Math.sqrt)
.duration(ring_anim_duration)
.remove();
var circle_container = circle_group.append('a');
circle_container.attr('xlink:href', data.url);
circle_container.attr('target', '_blank');
circle_container.attr('fill', svg_text_color);
var circle = circle_container.append('circle');
circle.classed(type, true);
circle.attr('r', size)
.attr('fill', edit_color)
.transition()
.duration(max_life)
.style('opacity', 0)
.remove();
circle_container.on('mouseover', function() {
circle_container.append('text')
.text(label_text)
.classed('label', true)
.attr('text-anchor', 'middle')
.attr('font-size', '0.8em')
.transition()
.delay(1000)
.style('opacity', 0)
.duration(2000)
.each(function() { no_label = true; })
.remove();
});
var text = circle_container.append('text')
.text(label_text)
.classed('article-label', true)
.attr('text-anchor', 'middle')
.attr('font-size', '0.8em')
.transition()
.delay(2000)
.style('opacity', 0)
.duration(5000)
.each(function() { no_label = true; })
.remove();
// Remove HTML of decayed events
// Keep it less than 50
if($('#area svg g').length > 50){
$('#area svg g:lt(10)').remove();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment