From cb4162bdfe0fd7a8da8b497773e8114f4406fce8 Mon Sep 17 00:00:00 2001 From: Hexagon Date: Sat, 20 Sep 2014 15:26:43 +0200 Subject: [PATCH] Notification sounds --- README.md | 2 + public/js/cryptalk_modules/cryptalk.js | 23 +++++++-- public/js/cryptalk_modules/queue.js | 48 +++++++++++++++++ public/js/cryptalk_modules/sound.js | 68 +++++++++++++++++++++++++ public/js/cryptalk_modules/templates.js | 5 ++ 5 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 public/js/cryptalk_modules/queue.js create mode 100644 public/js/cryptalk_modules/sound.js diff --git a/README.md b/README.md index b8a83e7..78f0bdc 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Features * Random (UUID v4) channel name generation för less guessability * Quick-links (not recommended) using http://server/#Room:Passphrase * Super simple setup + * Notification sounds (mutable) * ~~Flashing title on new messages~~ @@ -50,5 +51,6 @@ Available commands: /key OurStrongPassphrase Sets encryption key /leave Leave the room /clear Clear on-screen buffer + /mute Toggle notification sounds /help This ``` diff --git a/public/js/cryptalk_modules/cryptalk.js b/public/js/cryptalk_modules/cryptalk.js index 2b7fc01..a967579 100644 --- a/public/js/cryptalk_modules/cryptalk.js +++ b/public/js/cryptalk_modules/cryptalk.js @@ -5,13 +5,14 @@ define('cryptalk', { host: '' }, compiles: ['$'], - requires: ['templates'] + requires: ['templates','sound'] }, function ($, requires, data) { var socket, key, room, hash, nick, + mute = false, // Collection of DOM components components = { @@ -20,7 +21,8 @@ define('cryptalk', { }, // Shortcut - templates = requires.templates, + templates = requires.templates; + sound = requires.sound; // Adds a new message to the DOM post = function (type, text, clearChat, clearBuffer, nick) { @@ -93,6 +95,17 @@ define('cryptalk', { post('info', $.template(templates.messages.nick_set, { nick: nick})); }, + mute: function () { + // Set nick + mute = !mute; + + // Inform that the key has been set + if( mute ) + post('info', $.template(templates.messages.muted )); + else + post('info', $.template(templates.messages.unmuted )); + }, + join: function (payload) { return ( room @@ -204,8 +217,8 @@ define('cryptalk', { if (!decrypted) { post('error', templates.messages.unable_to_decrypt); } else { - // Post the message, but do not clear either the chat nor the buffer. post('message', sanitized, false, false, nick); + if( !mute ) sound.playTones(sound.messages.message); } }) @@ -219,6 +232,10 @@ define('cryptalk', { } else { post('server', templates.server[sanitized]); } + + // Play sound + if (sound.messages[sanitized] !== undefined && !mute ) sound.playTones(sound.messages[sanitized]); + } else { post('error', templates.server.bogus); } diff --git a/public/js/cryptalk_modules/queue.js b/public/js/cryptalk_modules/queue.js new file mode 100644 index 0000000..ce45d56 --- /dev/null +++ b/public/js/cryptalk_modules/queue.js @@ -0,0 +1,48 @@ +define('queue', function(){ + + var exports = {}; + + queue = []; + + exports.add_function_delayed = function(d,callback,data) { + + queue.push( + { + func: + function(){ + var finished = callback(); + }, + pushed:Date.now(), + delay:d, + data:data + } + ); + + } + + exports.get = function() { + return queue; + } + + exports.run = function(){ + + for(var i=0;i current.delay) { + current.func(); + queue.splice(i,1); + } + } + if(!queue.length) return; + + // Waste a ms to prevent callstack overflow + lrt_inner = Date.now(); + while (Date.now() - lrt_inner < 1) { var a=1+1; }; + + exports.run(); + + } + + return exports; + +}); \ No newline at end of file diff --git a/public/js/cryptalk_modules/sound.js b/public/js/cryptalk_modules/sound.js new file mode 100644 index 0000000..8d11570 --- /dev/null +++ b/public/js/cryptalk_modules/sound.js @@ -0,0 +1,68 @@ +// Sounds module, used for emitting those annoying bl-up sounds when receiving a message +define('sound',{requires: ['queue']}, function (requires) { + + var exports = { messages: {} }, + queue = requires.queue, + + ac = new (window.AudioContext || window.webkitAudioContext || false); + + // Recursive function for playing tones, takes an array of [tone,start_ms,duration_ms] - entries + // i is only used for recursion + exports.playTones = function (tones, i) { + + // Parameter defaults + i = (i === undefined) ? 0 : i; + + // Stop if we've reached the end of iteration, and require ac + if( !(i < Object.keys(tones).length) || !ac ) return; + + // Add tones to execution queue + var current_tones = tones[i], + freqs = current_tones[0], + start = current_tones[1], + duration = current_tones[2]; + + var o = ac.createOscillator(); + var g = ac.createGain(); + o.frequency.value = freqs; + o.connect(g); + g.gain.value = 0.25; + g.connect(ac.destination); + queue.add_function_delayed(start,function() { o.noteOn(0); }); + queue.add_function_delayed(start+duration,function() { o.noteOff(0); }); + + // Iterate, or start playing + i++; + if( i < Object.keys(tones).length ) { + exports.playTones(tones,i); + } else { + queue.run(); + + } + + }; + + exports.messages = { + message: [ + [261.63*2,0,50], + [261.63*3,0,50], + [261.63*4,50,50], + [261.63*5,50,50] + ], + person_joined: [ + [261.63*3,0,200], + [261.63*1,0,200], + [261.63*3,200,500], + [261.63*2,200,500] + ], + person_left: [ + [261.63*3,0,200], + [261.63*2,0,200], + [261.63*3,200,500], + [261.63*1,200,500] + ] + }; + + return exports; + +}); \ No newline at end of file diff --git a/public/js/cryptalk_modules/templates.js b/public/js/cryptalk_modules/templates.js index 4ff4d85..8535a5a 100644 --- a/public/js/cryptalk_modules/templates.js +++ b/public/js/cryptalk_modules/templates.js @@ -28,6 +28,7 @@ define({ ' /join RoomId Join a room \n' + ' /count Count participants of room \n' + ' /nick NickName Sets an optional nick \n' + + ' /mute Toggle notification sounds \n' + ' /key OurStrongPassphrase Sets encryption key \n' + ' /leave Leave the room \n' + ' /clear Clear on-screen buffer \n' + @@ -61,6 +62,10 @@ define({ nick_set: 'From now on, you\'re referred to as \'{nick}\'.', leave_from_nowhere: 'How are you supposed to leave, while being nowhere?', + // Sounds + muted: 'Notification sounds is now muted.', + unmuted: 'Notifications sounds is now on.', + // Available variables: 'commandName' unrecognized_command: 'Unrecognized command: "{commandName}"',