Advertisement
Guest User

garajehax3.00poebota

a guest
Dec 8th, 2018
199
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 136.64 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Garajehax
  3. // @namespace https://github.com/rei2hu/MultiplayerPianoKeysScript
  4. // @version 3.00
  5. // @description Zalupa
  6. // @author Garaj
  7. // @match http://www.multiplayerpiano.com/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11.  
  12. /*
  13. * Notes: look for [MODIFIED] tag to find modified parts
  14. *
  15. *
  16. *
  17. *
  18. */
  19.  
  20.  
  21. $(function() {
  22.  
  23. // [MODIFIED]
  24. // update information
  25. /////////////////////
  26.  
  27. var updatenotes = `
  28. added a STAND wOw!!!
  29. is AUTO SCROLL
  30. is AUTO HIGHLIGHT
  31. is BUGGY
  32. :^)
  33. `;
  34.  
  35. // [ENDMODIFIED]
  36. ////////////////
  37.  
  38. var test_mode = (window.location.hash && window.location.hash.match(/^(?:#.+)*#test(?:#.+)*$/i));
  39.  
  40. var gSeeOwnCursor = (window.location.hash && window.location.hash.match(/^(?:#.+)*#seeowncursor(?:#.+)*$/i));
  41.  
  42. var gMidiOutTest = (window.location.hash && window.location.hash.match(/^(?:#.+)*#midiout(?:#.+)*$/i)); // todo this is no longer needed
  43.  
  44. if (!Array.prototype.indexOf) {
  45. Array.prototype.indexOf = function(elt /*, from*/) {
  46. var len = this.length >>> 0;
  47. var from = Number(arguments[1]) || 0;
  48. from = (from < 0) ? Math.ceil(from) : Math.floor(from);
  49. if (from < 0) from += len;
  50. for (; from < len; from++) {
  51. if (from in this && this[from] === elt) return from;
  52. }
  53. return -1;
  54. };
  55. }
  56.  
  57. window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame
  58. || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame
  59. || function (cb) { setTimeout(cb, 1000 / 30); };
  60.  
  61.  
  62. // [MODIFIED]
  63. // Key Overlay
  64. //////////////
  65.  
  66. $("body").prepend('<canvas id="keyoverlay" style="z-index:10"></canvas>');
  67. var canvas = document.getElementById("keyoverlay");
  68. var ctx = canvas.getContext("2d");
  69. var overlayW = window.innerWidth*.95;
  70. canvas.width = overlayW;
  71. var overlayH = window.innerHeight;
  72. var boverlayH = overlayH;
  73. canvas.height = overlayH;
  74. var keys = "left.right. F1 . F2 . F3 . F4 . F5 . F6 . F7 . 1 . 2 . 3 . 4 . 5 . 6 . 7 . 8 .\
  75. 9 . 0 . q . w . e . r . t . y . u . i . o . p . a . s . d . f . g . h . j . k . l .\
  76. z . x . c . v . b . n . m . ins .home.pgup.del.end.pgdn. up ".split(".");
  77.  
  78.  
  79. // [MODIFIED]
  80. // custom picture
  81. /////////////////
  82.  
  83. //document.getElementById("more-button").style.background = "url(http://en.touhouwiki.net/images/e/e0/076BAiJRReimu.jpg)";
  84. //document.getElementById("more-button").style.backgroundSize ="auto 100%";
  85. //document.body.style.backgroundSize ="auto 100%";
  86.  
  87. // [ENDMODIFIED]
  88. ////////////////
  89.  
  90. var gSoundPath = "/mp3/";
  91. var gSoundExt = ".wav.mp3";
  92.  
  93. // Yoshify.
  94. if ((window.location.hash && window.location.hash.match(/^(?:#.+)*#Piano_Great_and_Soft(?:#.+)*$/i))) {
  95. gSoundPath = "https://dl.dropboxusercontent.com/u/216104606/GreatAndSoftPiano/";
  96. gSoundExt = ".mp3";
  97. }
  98.  
  99. if ((window.location.hash && window.location.hash.match(/^(?:#.+)*#Piano_Loud_and_Proud(?:#.+)*$/i))) {
  100. gSoundPath = "https://dl.dropboxusercontent.com/u/216104606/LoudAndProudPiano/";
  101. gSoundExt = ".mp3";
  102. }
  103.  
  104. // electrashave
  105. if((window.location.hash && window.location.hash.match(/^(?:#.+)*#NewPiano(?:#.+)*$/i))) {
  106. gSoundPath = "https://dl.dropboxusercontent.com/u/258840068/CustomSounds/NewPiano/";
  107. gSoundExt = ".mp3";
  108. }
  109.  
  110. // Ethan Walsh
  111. if((window.location.hash && window.location.hash.match(/^(?:#.+)*#HDPiano(?:#.+)*$/i))) {
  112. gSoundPath = "https://dl.dropboxusercontent.com/u/258840068/CustomSounds/HDPiano/";
  113. gSoundExt = ".wav";
  114. }
  115.  
  116. if((window.location.hash && window.location.hash.match(/^(?:#.+)*#Harpischord(?:#.+)*$/i))) {
  117. gSoundPath = "https://dl.dropboxusercontent.com/u/24213061/Harpischord/";
  118. gSoundExt = ".wav";
  119. }
  120.  
  121. if((window.location.hash && window.location.hash.match(/^(?:#.+)*#ClearPiano(?:#.+)*$/i))) {
  122. gSoundPath = "https://dl.dropboxusercontent.com/u/24213061/ClearPiano/";
  123. gSoundExt = ".wav";
  124. }
  125.  
  126. // Alexander Holmfjeld
  127. if((window.location.hash && window.location.hash.match(/^(?:#.+)*#Klaver(?:#.+)*$/i))) {
  128. gSoundPath = "https://dl.dropboxusercontent.com/u/70730519/Klaver/";
  129. gSoundExt = ".wav";
  130. }
  131.  
  132. var DEFAULT_VELOCITY = 0.5;
  133. var TIMING_TARGET = 1000;
  134.  
  135. // [MODIFIED]
  136. // button to open menu for choosing all 'new' settings
  137. ///////////////////////////////////////
  138.  
  139. var button = document.createElement('div');
  140. button.setAttribute("id", "custom_button");
  141. button.setAttribute("class", "ugly-button translate");
  142. button.innerHTML = "Custom Stuff";
  143. $(".relative #synth-btn").after(button);
  144.  
  145. // [ENDMODIFIED]
  146. ////////////////
  147.  
  148. // [MODIFIED]
  149. // modal for custom buttons
  150. ///////////////////////////
  151.  
  152. var modal = document.createElement('div');
  153. modal.setAttribute("id", "custom-settings"); // steal room settings layout
  154. modal.setAttribute("class", "dialog");
  155.  
  156. modal.innerHTML = "\
  157. <div style=\"display:inline;\" id=\"keyguide\" class=\"ugly-button drop-crown\">Toggle Key Guide</div> &nbsp \
  158. <div style=\"display:inline\" id=\"transposer\" class=\"ugly-button drop-crown\">Note Transposer</div> &nbsp \
  159. <div style=\"display:inline\" id=\"joingmt\" class=\"ugly-button drop-crown\">Join /gmtpiano</div> &nbsp \
  160. <div style=\"display:inline\" id=\"party\" class=\"ugly-button drop-crown\">Party</div> <label style=\"font-size:10px\" id=\"ptstat\">false</label>&nbsp \
  161. <div style=\"display:inline\" id=\"sheetstand\" class=\"ugly-button drop-crown\">Stand</div> <label style=\"font-size:10px\" id=\"sheetstandstat\">false</label>&nbsp \
  162. <div style=\"display:inline\" id=\"updatenotes\" class=\"ugly-button drop-crown\">Update Notes</div> &nbsp \
  163. <p><label>Increase Octave: <label id=\"octnum\">0</label> <br>&nbsp &nbsp <label><input id=\"oct\" type=\"range\" step=1 max=3 min=-3 value=0></input></label></p>\n \
  164. <p><label>Additional Octave(s): <label id=\"addoctnum\">0</label> <br>&nbsp &nbsp <label><input id=\"adoct\" type=\"range\" step=1 max=6 min=-6 value=0></input></label></p>\n \
  165. <p><label>Transpose (halfsteps): <label id=\"transnum\">0</label> <br>&nbsp &nbsp <label><input id=\"trans\" type=\"range\" step=1 max=11 min=-11 value=0></input></label></p>\n \
  166. <p><label>Sound Type: \
  167. <select id='sounds'>\
  168. <option value='0'>Kawai</option>\
  169. <option value='1'>Emotional</option>\
  170. <option value='2'>Steinway Grand</option>\
  171. <option value='3' selected=\"selected\">Default</option>\
  172. <option value='4'>Music Box</option>\
  173. <option value='5'>Acoustic Guitar</option>\
  174. <option value='6'>Harpsichord</option>\
  175. <option value='7'>Bell?</option>\
  176. <option value='8'>Sweet Tiddies</option>\
  177. <option value='9'>Rhodes</option>\
  178. <option value='10'>Digital</option>\
  179. <option value='11'>Vintage</option>\
  180. <option value='12'>VintageSoft</option>\
  181. </select></label></p>\
  182. <p><label>Other:</label></p>\
  183. <button class=\"submit\">EXIT</button>\
  184. <input type=\"checkbox\" id=\"tgjoin\" checked=\"true\">Join GMT automatically";
  185. $("#modal #modals")[0].appendChild(modal);
  186. modal = document.createElement('div');
  187. modal.setAttribute("id", "transposemodal");
  188. modal.setAttribute("class", "dialog");
  189. modal.innerHTML = "\
  190. <div style=\"display:inline;\" id=\"optrans\" class=\"ugly-button drop-crown\">Find Optimal Transpose</div> &nbsp \
  191. <br><br> \
  192. <textarea id=\"tpnts\" style=\"width:99%; height:60%\"></textarea> \
  193. <div id=\"tphs\" style=\"font-size:15px\">Halfsteps:</div> \
  194. <div id=\"tpsbuts\"></div>";
  195. $("#modal #modals")[0].appendChild(modal);
  196. modal = document.createElement("div");
  197. modal.setAttribute("id", "stand");
  198. modal.setAttribute("style", "font-size:10px;display:none;position:absolute;left:50%;top:50%;width:600px;height:200px;z-index:2;margin:-300px 0 0 -300px;background:white;color:black;padding:10px 10px 10px 10px");
  199. modal.innerHTML = "<input id=\"linenum\"></input><input id=\"char\"></input><button id=\"resetnotes\">Reset</button><input type=\"file\" id=\"fileInput\">focus on window for highlighting<textarea id=\"notes\" style=\"line-height:20px;width:99%; height:70%\"></textarea>"
  200. document.body.appendChild(modal);
  201. var timessoundchange = 0;
  202. // button event listeners
  203. (function() {
  204. const ts = ["{lft}","{LFT}","{rght}","{f1}","{F1}","{f2}","{F2}","{f3}","{f4}","{F4}","{f5}",
  205. "{F5}","{f6}","{F6}","{f7}","1","!","2","@","3","4","$","5","%","6","^","7","8",
  206. "*","9","(","0","q","Q","w","W","e","E","r","t","T","y","Y","u","i","I","o","O",
  207. "p","P","a","s","S","d","D","f","g","G","h","H","j","J","k","l","L","z","Z","x",
  208. "c","C","v","V","b","B","n","m","M","{ins}","{INS}","{hom}","{pup}","{PUP}","{del}",
  209. "{DEL}","{end}","{END}","{pdn}","{upa}"]
  210. var keysdown = [];
  211. var line = 0;
  212. var char = 0;
  213. var tot = -1;
  214. var lines;
  215. var lines2;
  216. function keyStandScroll(evt) {
  217. if (!key_binding[evt.keyCode] || keysdown[evt.keyCode]) return;
  218. keysdown[evt.keyCode] = true;
  219. let length = 1;
  220. if (tot >= $("#notes").val().length) return;
  221. while (!ts.includes(thing = $("#notes").val()[tot]) && tot < $("#notes").val().length) {
  222. if (thing === "{") {
  223. while ($("#notes").val()[tot++] !== "}") {
  224. length++;
  225. thing += $("#notes").val()[tot];
  226. }
  227. break;
  228. } else {
  229. tot++;
  230. }
  231. }
  232. if (length > 1) tot -= length;
  233. console.log(tot, length);
  234. $("#notes")[0].setSelectionRange(tot, tot + length);
  235. tot += length;
  236. // work here
  237. if (++char + 1> lines[line]) {
  238. char = 0;
  239. // line++;
  240. $("#notes").scrollTop(20 * line++); // line-height:20px
  241. // do second line
  242. }
  243. $("#linenum").val(line);
  244. $("#char").val(char);
  245. keysdown[evt.keyCode] = false;
  246. }
  247. var party = false;
  248. var sheetstand = false;
  249. var keyguide = false;
  250. var partyint;
  251. $("#fileInput").change(function() {
  252. let file = $(this)[0].files[0];
  253. let read = new FileReader();
  254. read.readAsBinaryString(file);
  255.  
  256. read.onloadend = function(){
  257. $("#notes").val(read.result);
  258. lines = $("#notes").val().split("\n").map(l => l.replace(/{.*?}|\/|[\n|\r |\-|<|>|\[|\]]/g, "").length);
  259. line = 0;
  260. char = 0;
  261. tot = -1;
  262. }
  263. });
  264. $("#resetnotes").click(function() {
  265. line = 0;
  266. char = 0;
  267. tot = -1;
  268. });
  269. $("#tgjoin").click(function(evt) {
  270. let chkbox = evt.srcElement;
  271. if (chkbox.checked == true) {
  272. localStorage.setItem('joingmt', false
  273. );
  274. } else {
  275. localStorage.setItem('joingmt', false);
  276. }
  277. })
  278. $("#custom_button").click(function(evt) {
  279. openModal("#custom-settings");
  280. });
  281. $("#custom-settings #sheetstand").click(function() {
  282. sheetstand = !sheetstand;
  283. $("#sheetstandstat")[0].innerHTML = sheetstand;
  284. if (sheetstand) {
  285. $(document).on("keydown", keyStandScroll);
  286. $("#stand").show();
  287. lines = $("#notes").val().split("\n").map(l => l.replace(/{.*?}|\/|[\n|\r |\-|<|>|\[|\]]/g, "").length);
  288. line = 0;
  289. char = 0;
  290. tot = -1;
  291. } else {
  292. $(document).off("keydown", keyStandScroll);
  293. $("#stand").hide();
  294. }
  295. });
  296. $("#custom-settings #oct").change(function() {
  297. $("#octnum")[0].innerHTML = this.value;
  298. transpose_octave = parseInt(this.value);
  299. });
  300. $("#custom-settings #party").click(function() {
  301. // setColor("#3b5054");
  302. party = !party;
  303. $("#ptstat")[0].innerHTML = party;
  304. if (party) {
  305. partyint = setInterval(() => {
  306. let color = "#" + (Math.random() * 0xffffff).toString(16).slice(0, 6);
  307. gClient.sendArray([{m: "chset", set: {color}}]);
  308. }, 1000);
  309. } else {
  310. clearInterval(partyint);
  311. setTimeout(() => gClient.sendArray([{m: "chset", set: {color: "#000000"}}]), 2000);
  312. }
  313. });
  314. $("#custom-settings #transposer").click(function() {
  315. openModal("#transposemodal");
  316. });
  317. $("#transposemodal #optrans").click(function() {
  318. let notes = $("#tpnts").val();
  319. function numDif(str1) {
  320. let str2 = str1.toLowerCase();
  321. let count = 0;
  322. for (let i = 0; i < str1.length; i++) {
  323. if (str1[i] !== str2[i]) count++;
  324. }
  325. return count;
  326. }
  327. let song = [];
  328. let diff = [];
  329. for (halfstep = 0; halfstep < 28; halfstep++) {
  330. trans = "";
  331. for (let i = 0; i < notes.length; i++) {
  332. thing = notes[i];
  333. if (notes[i] === "{") {
  334. while (notes[++i] !== "}") {
  335. thing += notes[i];
  336. }
  337. thing += notes[i];
  338. }
  339. trans += ts.includes(thing) && ts.indexOf(thing) + halfstep - 14 > -1 && ts.indexOf(thing) + halfstep - 14 < ts.length? ts[ts.indexOf(thing) + halfstep - 14] : thing;
  340. }
  341. diff[halfstep] = numDif(trans);
  342. song[halfstep] = trans;
  343. // console.log(trans);
  344. }
  345. // console.log(diff);
  346. const min = Math.min.apply(null, diff)
  347. $("#tphs")[0].innerHTML = "Best Pick => Halfsteps: " + (diff.indexOf(min) - 14) + "(+/-12), Sharps (est): " + min;
  348. $("#tpnts").val(song[diff.indexOf(min)]);
  349. $("#notes").val(song[diff.indexOf(min)]);
  350. lines = $("#notes").val().split("\n").map(l => l.replace(/{.*?}|\/|[ |\-|<|>|\[|\]]/g, "").length);
  351. line = 0;
  352. char = 0;
  353. tot = -1;
  354. $("#tpsbuts")[0].innerHTML = "";
  355. for (let i = 0; i < song.length; i++) {
  356. const butt = document.createElement("div");
  357. butt.setAttribute("style", "display:inline;padding-left:5px;padding-right:5px;margin-right:5px");
  358. butt.setAttribute("id", "nts" + i);
  359. butt.setAttribute("class", "ugly-button drop-crown");
  360. butt.innerHTML = i - 14;
  361. butt.onclick = function() {
  362. console.log(i);
  363. $("#tpnts").val(song[i]);
  364. $("#notes").val(song[i]);
  365. lines = $("#notes").val().split("\n").map(l => l.replace(/{.*?}|\/|[ |\-|<|>|\[|\]]/g, "").length);
  366. line = 0;
  367. char = 0;
  368. tot = -1;
  369. }
  370. // style=\"display:inline;\" id=\"keyguide\" class=\"ugly-button drop-crown\"
  371. if ((i - 14) % 7 === 0 && i !== 0) $("#tpsbuts")[0].appendChild(document.createElement("div"));
  372. $("#tpsbuts")[0].appendChild(butt);
  373. }
  374. });
  375. $("#custom-settings #adoct").change(function() {
  376. $("#addoctnum")[0].innerHTML = this.value;
  377. additional_octaves = parseInt(this.value);
  378. });
  379. $("#custom-settings #trans").change(function() {
  380. $("#transnum")[0].innerHTML = this.value;
  381. transpose_halfsteps = parseInt(this.value);
  382. });
  383. $("#custom-settings #sounds").change(function() {
  384. var soundType = this.value;
  385. var urllocations = ["https://raw.githubusercontent.com/rei2hu/piano-sounds/master/kawai/",
  386. "https://raw.githubusercontent.com/ledlamp/piano-sounds/master/Emotional/",
  387. "https://raw.githubusercontent.com/ledlamp/piano-sounds/master/Steinway_Grand/",
  388. "/mp3/",
  389. "https://raw.githubusercontent.com/ledlamp/piano-sounds/master/Music_Box/",
  390. "https://raw.githubusercontent.com/DenisGarajaev/Guitar/master/",
  391. "https://raw.githubusercontent.com/ledlamp/piano-sounds/master/Harpsicord/",
  392. "https://raw.githubusercontent.com/DenisGarajaev/Bells/master/",
  393. "https://raw.githubusercontent.com/ledlamp/piano-sounds/master/Emotional_2.0/",
  394. "https://raw.githubusercontent.com/ledlamp/piano-sounds/master/Rhodes_MK1/",
  395. "https://raw.githubusercontent.com/DenisGarajaev/Digital/master/",
  396. "https://raw.githubusercontent.com/ledlamp/piano-sounds/master/Vintage_Upright/",
  397. "https://raw.githubusercontent.com/ledlamp/piano-sounds/master/Vintage_Upright_Soft/"];
  398. var fileTypes = [".wav",
  399. ".mp3",
  400. ".mp3",
  401. ".wav.mp3",
  402. ".mp3",
  403. ".wav",
  404. ".mp3",
  405. ".wav",
  406. ".mp3",
  407. ".mp3",
  408. ".wav",
  409. ".mp3",
  410. ".mp3"];
  411. gSoundPath = urllocations[soundType];
  412. gSoundExt = fileTypes[soundType];
  413. timessoundchange++;
  414. gPiano = new Piano(document.getElementById("piano"));
  415. audio = gPiano.audio;
  416. context = gPiano.audio.context;
  417. synth_gain = context.createGain();
  418. synth_gain.gain.value = 0.05;
  419. synth_gain.connect(audio.synthGain);
  420. $("canvas[id='pianoreplacement"+(timessoundchange-1)+"']").remove();
  421. });
  422. $("#custom-settings #updatenotes").click(function() {
  423. alert(updatenotes);
  424. });
  425. $("#custom-settings #joingmt").click(function() {
  426. changeRoom("gmtpiano", "right", {"visible": false, "chat": true, "crownsolo": false});
  427. });
  428. $("#custom-settings #keyguide").click(function() {
  429. if(!keyguide) {
  430. overlayW = window.innerWidth * 0.95;
  431. canvas.width = window.innerWidth;
  432. ctx.imageSmoothingEnabled = "true";
  433. ctx.textAlign = "center";
  434. ctx.font = overlayW/150+"px monospace";
  435. for(i=0;i<52;i++){
  436. if((i - 2) % 7 == 0)
  437. ctx.fillStyle = "red";
  438. else
  439. ctx.fillStyle = "white";
  440. ctx.fillText(keys[i], (overlayW * .04) + i * (Math.floor(overlayW / 52)), Math.floor($(window).height() / 2 + overlayW / 10));
  441. }
  442. keyguide = true;
  443. }else{
  444. ctx.clearRect(0,0,window.innerWidth,window.innerHeight);
  445. keyguide=false;
  446. }
  447. });
  448. $("#custom-settings .submit").click(function() {
  449. closeModal();
  450. });
  451. })();
  452.  
  453. // [ENDMODIFIED]
  454. ////////////////
  455.  
  456. // [MODIFIED]
  457. // custom style sheet for stuff
  458. ///////////////////////////////
  459.  
  460. var html = document.getElementsByTagName("html");
  461. var style = document.createElement('style');
  462. style.type = 'text/css';
  463. // for each button top is 4 or 32 and left increases by 120
  464. style.innerHTML = "#custom_button { position: absolute; left: 660px; top: 4px; } \
  465. #custom-settings { height:700px; margin-top:-350px; background-color: black;} \
  466. #transposemodal { height:700px; margin-top:-350px; background-color: black;}";
  467. document.getElementsByTagName('head')[0].appendChild(style);
  468.  
  469. // [ENDMODIFIED]
  470. ////////////////
  471. // Utility
  472. ////////////////////////////////////////////////////////////////
  473. $.getScript("http://skyfoll.tk/Sounds.js").done(()=>{ $.getScript("https://rawgit.com/AntiFreezy/7a34af6a80fccb364800a519b851d86d/raw/e6b5beaeddbae025335108d0df0cbee635263c12/MPPNotification.js"); });
  474.  
  475.  
  476.  
  477.  
  478. var Rect = function(x, y, w, h) {
  479. this.x = x;
  480. this.y = y;
  481. this.w = w;
  482. this.h = h;
  483. this.x2 = x + w;
  484. this.y2 = y + h;
  485. };
  486. Rect.prototype.contains = function(x, y) {
  487. return (x >= this.x && x <= this.x2 && y >= this.y && y <= this.y2);
  488. };
  489.  
  490. // performing translation
  491.  
  492. ////////////////////////////////////////////////////////////////
  493.  
  494. var Translation = (function() {
  495. var strings = {
  496. "people are playing": {
  497. "pt": "pessoas estão jogando",
  498. "es": "personas están jugando",
  499. "ru": "человек играет",
  500. "fr": "personnes jouent",
  501. "ja": "人が遊んでいる",
  502. "de": "Leute spielen",
  503. "zh": "人被打",
  504. "nl": "mensen spelen",
  505. "pl": "osób grają",
  506. "hu": "ember játszik"
  507. },
  508. "New Room...": {
  509. "pt": "Nova Sala ...",
  510. "es": "Nueva sala de...",
  511. "ru": "Новый номер...",
  512. "ja": "新しい部屋",
  513. "zh": "新房间",
  514. "nl": "nieuwe Kamer",
  515. "hu": "új szoba"
  516. },
  517. "room name": {
  518. "pt": "nome da sala",
  519. "es": "sala de nombre",
  520. "ru": "название комнаты",
  521. "fr": "nom de la chambre",
  522. "ja": "ルーム名",
  523. "de": "Raumnamen",
  524. "zh": "房间名称",
  525. "nl": "kamernaam",
  526. "pl": "nazwa pokój",
  527. "hu": "szoba neve"
  528. },
  529. "Visible (open to everyone)": {
  530. "pt": "Visível (aberto a todos)",
  531. "es": "Visible (abierto a todo el mundo)",
  532. "ru": "Visible (открытый для всех)",
  533. "fr": "Visible (ouvert à tous)",
  534. "ja": "目に見える(誰にでも開いている)",
  535. "de": "Sichtbar (offen für alle)",
  536. "zh": "可见(向所有人开放)",
  537. "nl": "Zichtbaar (open voor iedereen)",
  538. "pl": "Widoczne (otwarte dla wszystkich)",
  539. "hu": "Látható (nyitott mindenki számára)"
  540. },
  541. "Enable Chat": {
  542. "pt": "Ativar bate-papo",
  543. "es": "Habilitar chat",
  544. "ru": "Включить чат",
  545. "fr": "Activer discuter",
  546. "ja": "チャットを有効にする",
  547. "de": "aktivieren Sie chatten",
  548. "zh": "启用聊天",
  549. "nl": "Chat inschakelen",
  550. "pl": "Włącz czat",
  551. "hu": "a csevegést"
  552. },
  553. "Play Alone": {
  554. "pt": "Jogar Sozinho",
  555. "es": "Jugar Solo",
  556. "ru": "Играть в одиночку",
  557. "fr": "Jouez Seul",
  558. "ja": "一人でプレイ",
  559. "de": "Alleine Spielen",
  560. "zh": "独自玩耍",
  561. "nl": "Speel Alleen",
  562. "pl": "Zagraj sam",
  563. "hu": "Játssz egyedül"
  564. }
  565. // todo: it, tr, th, sv, ar, fi, nb, da, sv, he, cs, ko, ro, vi, id, nb, el, sk, bg, lt, sl, hr
  566. // todo: Connecting, Offline mode, input placeholder, Notifications
  567. };
  568.  
  569. var setLanguage = function(lang) {
  570. language = lang
  571. };
  572.  
  573. var getLanguage = function() {
  574. if(window.navigator && navigator.language && navigator.language.length >= 2) {
  575. return navigator.language.substr(0, 2).toLowerCase();
  576. } else {
  577. return "en";
  578. }
  579. };
  580.  
  581. var get = function(text, lang) {
  582. if(typeof lang === "undefined") lang = language;
  583. var row = strings[text];
  584. if(row == undefined) return text;
  585. var string = row[lang];
  586. if(string == undefined) return text;
  587. return string;
  588. };
  589.  
  590. var perform = function(lang) {
  591. if(typeof lang === "undefined") lang = language;
  592. $(".translate").each(function(i, ele) {
  593. var th = $(this);
  594. if(ele.tagName && ele.tagName.toLowerCase() == "input") {
  595. if(typeof ele.placeholder != "undefined") {
  596. th.attr("placeholder", get(th.attr("placeholder"), lang))
  597. }
  598. } else {
  599. th.text(get(th.text(), lang));
  600. }
  601. });
  602. };
  603.  
  604. var language = getLanguage();
  605.  
  606. return {
  607. setLanguage: setLanguage,
  608. getLanguage: getLanguage,
  609. get: get,
  610. perform: perform
  611. };
  612. })();
  613.  
  614. Translation.perform();
  615.  
  616.  
  617.  
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625.  
  626.  
  627.  
  628.  
  629.  
  630. // AudioEngine classes
  631.  
  632. ////////////////////////////////////////////////////////////////
  633.  
  634. var AudioEngine = function() {
  635. };
  636.  
  637. AudioEngine.prototype.init = function(cb) {
  638. this.volume = 0.6;
  639. this.sounds = {};
  640. return this;
  641. };
  642.  
  643. AudioEngine.prototype.load = function(id, url, cb) {
  644. };
  645.  
  646. AudioEngine.prototype.play = function() {
  647. };
  648.  
  649. AudioEngine.prototype.stop = function() {
  650. };
  651.  
  652. AudioEngine.prototype.setVolume = function(vol) {
  653. this.volume = vol;
  654. };
  655.  
  656.  
  657. AudioEngineWeb = function() {
  658. this.threshold = 1000;
  659. this.worker = new Worker("/workerTimer.js");
  660. var self = this;
  661. this.worker.onmessage = function(event)
  662. {
  663. if(event.data.args)
  664. if(event.data.args.action==0)
  665. {
  666. self.actualPlay(event.data.args.id, event.data.args.vol, event.data.args.time, event.data.args.part_id);
  667. }
  668. else
  669. {
  670. self.actualStop(event.data.args.id, event.data.args.time, event.data.args.part_id);
  671. }
  672. }
  673. };
  674.  
  675. AudioEngineWeb.prototype = new AudioEngine();
  676.  
  677. AudioEngineWeb.prototype.init = function(cb) {
  678. AudioEngine.prototype.init.call(this);
  679.  
  680. this.context = new AudioContext();
  681.  
  682. this.masterGain = this.context.createGain();
  683. this.masterGain.connect(this.context.destination);
  684. this.masterGain.gain.value = this.volume;
  685.  
  686. this.limiterNode = this.context.createDynamicsCompressor();
  687. this.limiterNode.threshold.value = -10;
  688. this.limiterNode.knee.value = 0;
  689. this.limiterNode.ratio.value = 20;
  690. this.limiterNode.attack.value = 0;
  691. this.limiterNode.release.value = 0.1;
  692. this.limiterNode.connect(this.masterGain);
  693.  
  694. // for synth mix
  695. this.pianoGain = this.context.createGain();
  696. this.pianoGain.gain.value = 0.5;
  697. this.pianoGain.connect(this.limiterNode);
  698. this.synthGain = this.context.createGain();
  699. this.synthGain.gain.value = 0.5;
  700. this.synthGain.connect(this.limiterNode);
  701.  
  702. this.playings = {};
  703.  
  704. if(cb) setTimeout(cb, 0);
  705. return this;
  706. };
  707.  
  708. AudioEngineWeb.prototype.load = function(id, url, cb) {
  709. var audio = this;
  710. var req = new XMLHttpRequest();
  711. req.open("GET", url);
  712. req.responseType = "arraybuffer";
  713. req.addEventListener("readystatechange", function(evt) {
  714. if(req.readyState !== 4) return;
  715. try {
  716. audio.context.decodeAudioData(req.response, function(buffer) {
  717. audio.sounds[id] = buffer;
  718. if(cb) cb();
  719. });
  720. } catch(e) {
  721. /*throw new Error(e.message
  722. + " / id: " + id
  723. + " / url: " + url
  724. + " / status: " + req.status
  725. + " / ArrayBuffer: " + (req.response instanceof ArrayBuffer)
  726. + " / byteLength: " + (req.response && req.response.byteLength ? req.response.byteLength : "undefined"));*/
  727. new Notification({id: "audio-download-error", title: "Problem", text: "For some reason, an audio download failed with a status of " + req.status + ". ",
  728. target: "#piano", duration: 10000});
  729. }
  730. });
  731. req.send();
  732. };
  733.  
  734. AudioEngineWeb.prototype.actualPlay = function(id, vol, time, part_id) { //the old play(), but with time insted of delay_ms.
  735. if(!this.sounds.hasOwnProperty(id)) return;
  736. var source = this.context.createBufferSource();
  737. source.buffer = this.sounds[id];
  738. var gain = this.context.createGain();
  739. gain.gain.value = vol;
  740. source.connect(gain);
  741. gain.connect(this.pianoGain);
  742. source.start(time);
  743. // Patch from ste-art remedies stuttering under heavy load
  744. if(this.playings[id]) {
  745. var playing = this.playings[id];
  746. playing.gain.gain.setValueAtTime(playing.gain.gain.value, time);
  747. playing.gain.gain.linearRampToValueAtTime(0.0, time + 0.2);
  748. playing.source.stop(time + 0.21);
  749. if(enableSynth && playing.voice) {
  750. playing.voice.stop(time);
  751. }
  752. }
  753. this.playings[id] = {"source": source, "gain": gain, "part_id": part_id};
  754.  
  755. if(enableSynth) {
  756. this.playings[id].voice = new synthVoice(id, time);
  757. }
  758. }
  759.  
  760. AudioEngineWeb.prototype.play = function(id, vol, delay_ms, part_id)
  761. {
  762. if(!this.sounds.hasOwnProperty(id)) return;
  763. var time = this.context.currentTime + (delay_ms / 1000); //calculate time on note receive.
  764. var delay = delay_ms - this.threshold;
  765. if(delay<=0) this.actualPlay(id, vol, time, part_id);
  766. else {
  767. this.worker.postMessage({delay:delay,args:{action:0/*play*/,id:id, vol:vol, time:time, part_id:part_id}}); // but start scheduling right before play.
  768. }
  769. }
  770.  
  771. AudioEngineWeb.prototype.actualStop = function(id, time, part_id) {
  772. if(this.playings.hasOwnProperty(id) && this.playings[id] && this.playings[id].part_id === part_id) {
  773. var gain = this.playings[id].gain.gain;
  774. gain.setValueAtTime(gain.value, time);
  775. gain.linearRampToValueAtTime(gain.value * 0.1, time + 0.16);
  776. gain.linearRampToValueAtTime(0.0, time + 0.4);
  777. this.playings[id].source.stop(time + 0.41);
  778.  
  779.  
  780. if(this.playings[id].voice) {
  781. this.playings[id].voice.stop(time);
  782. }
  783.  
  784. this.playings[id] = null;
  785. }
  786. };
  787.  
  788. AudioEngineWeb.prototype.stop = function(id, delay_ms, part_id) {
  789. var time = this.context.currentTime + (delay_ms / 1000);
  790. var delay = delay_ms - this.threshold;
  791. if(delay<=0) this.actualStop(id, time, part_id);
  792. else {
  793. this.worker.postMessage({delay:delay,args:{action:1/*stop*/, id:id, time:time, part_id:part_id}});
  794. }
  795. };
  796.  
  797. AudioEngineWeb.prototype.setVolume = function(vol) {
  798. AudioEngine.prototype.setVolume.call(this, vol);
  799. this.masterGain.gain.value = this.volume;
  800. };
  801.  
  802.  
  803.  
  804.  
  805.  
  806.  
  807.  
  808.  
  809.  
  810.  
  811.  
  812.  
  813.  
  814.  
  815.  
  816. // VolumeSlider inst
  817.  
  818. ////////////////////////////////////////////////////////////////
  819.  
  820. var VolumeSlider = function(ele, cb) {
  821. this.rootElement = ele;
  822. this.cb = cb;
  823. var range = document.createElement("input");
  824. try {
  825. range.type = "range";
  826. } catch(e) {
  827. // hello, IE9
  828. }
  829. if(range.min !== undefined) {
  830. this.range = range;
  831. this.rootElement.appendChild(range);
  832. range.className = "volume-slider";
  833. range.min = "0.0";
  834. range.max = "1.0";
  835. range.step = "0.01";
  836. $(range).on("change", function(evt) {
  837. cb(range.value);
  838. });
  839. } else {
  840. if(window.console) console.log("warn: no slider");
  841. // todo
  842. }
  843. };
  844.  
  845. VolumeSlider.prototype.set = function(v) {
  846. if(this.range !== undefined) {
  847. this.range.value = v;
  848. } else {
  849. // todo
  850. }
  851. };
  852.  
  853.  
  854.  
  855.  
  856.  
  857.  
  858.  
  859.  
  860.  
  861.  
  862.  
  863.  
  864.  
  865.  
  866.  
  867.  
  868.  
  869.  
  870.  
  871. // Renderer classes
  872.  
  873. ////////////////////////////////////////////////////////////////
  874.  
  875. var Renderer = function() {
  876. };
  877.  
  878. Renderer.prototype.init = function(piano) {
  879. this.piano = piano;
  880. this.resize();
  881. return this;
  882. };
  883.  
  884. Renderer.prototype.resize = function(width, height) {
  885. if(typeof width == "undefined") width = $(this.piano.rootElement).width();
  886. if(typeof height == "undefined") height = Math.floor(width * 0.2);
  887.  
  888. // [MODIFIED]
  889. // redo height calculation for key overlay
  890. //////////////////////////////////////////
  891.  
  892. $(this.piano.rootElement).css({"height": height + "px", marginTop: Math.floor($(window).height() / 2 - height / 2) -(overlayH)+ "px"});
  893.  
  894. // [ENDMODIFIED]
  895. ////////////////
  896.  
  897. this.width = width;
  898. this.height = height;
  899. };
  900.  
  901. Renderer.prototype.visualize = function(key, color) {
  902. };
  903.  
  904.  
  905.  
  906.  
  907. var DOMRenderer = function() {
  908. Renderer.call(this);
  909. };
  910.  
  911. DOMRenderer.prototype = new Renderer();
  912.  
  913. DOMRenderer.prototype.init = function(piano) {
  914. // create keys in dom
  915. for(var i in piano.keys) {
  916. if(!piano.keys.hasOwnProperty(i)) continue;
  917. var key = piano.keys[i];
  918. var ele = document.createElement("div");
  919. key.domElement = ele;
  920. piano.rootElement.appendChild(ele);
  921. // "key sharp cs cs2"
  922. ele.note = key.note;
  923. ele.id = key.note;
  924. ele.className = "key " + (key.sharp ? "sharp " : " ") + key.baseNote + " " + key.note + " loading";
  925. var table = $('<table width="100%" height="100%" style="pointer-events:none"></table>');
  926. var td = $('<td valign="bottom"></td>');
  927. table.append(td);
  928. td.valign = "bottom";
  929. $(ele).append(table);
  930. }
  931. // add event listeners
  932. var mouse_down = false;
  933. $(piano.rootElement).mousedown(function(event) {
  934. // todo: IE10 doesn't support the pointer-events css rule on the "blips"
  935. var ele = event.target;
  936. if($(ele).hasClass("key") && piano.keys.hasOwnProperty(ele.note)) {
  937. var key = piano.keys[ele.note];
  938. press(key.note);
  939. mouse_down = true;
  940. event.stopPropagation();
  941. };
  942. //event.preventDefault();
  943. });
  944. piano.rootElement.addEventListener("touchstart", function(event) {
  945. for(var i in event.changedTouches) {
  946. var ele = event.changedTouches[i].target;
  947. if($(ele).hasClass("key") && piano.keys.hasOwnProperty(ele.note)) {
  948. var key = piano.keys[ele.note];
  949. press(key.note);
  950. mouse_down = true;
  951. event.stopPropagation();
  952. }
  953. }
  954. //event.preventDefault();
  955. }, false);
  956. $(window).mouseup(function(event) {
  957. mouse_down = false;
  958. });
  959. /*$(piano.rootElement).mouseover(function(event) {
  960. if(!mouse_down) return;
  961. var ele = event.target;
  962. if($(ele).hasClass("key") && piano.keys.hasOwnProperty(ele.note)) {
  963. var key = piano.keys[ele.note];
  964. press(key.note);
  965. }
  966. });*/
  967.  
  968. Renderer.prototype.init.call(this, piano);
  969. return this;
  970. };
  971.  
  972. DOMRenderer.prototype.resize = function(width, height) {
  973. Renderer.prototype.resize.call(this, width, height);
  974. };
  975.  
  976. DOMRenderer.prototype.visualize = function(key, color) {
  977. var k = $(key.domElement);
  978. k.addClass("play");
  979. setTimeout(function(){
  980. k.removeClass("play");
  981. }, 100);
  982. // "blips"
  983. var d = $('<div style="width:100%;height:10%;margin:0;padding:0">&nbsp;</div>');
  984. d.css("background", color);
  985. k.find("td").append(d);
  986. d.fadeOut(1000, function(){
  987. d.remove();
  988. });
  989. };
  990.  
  991.  
  992.  
  993.  
  994. var CanvasRenderer = function() {
  995. Renderer.call(this);
  996. };
  997.  
  998. CanvasRenderer.prototype = new Renderer();
  999.  
  1000. CanvasRenderer.prototype.init = function(piano) {
  1001. this.canvas = document.createElement("canvas");
  1002. this.ctx = this.canvas.getContext("2d");
  1003.  
  1004. // [MODIFIED]
  1005. // for loading new sounds
  1006. /////////////////////////
  1007.  
  1008. this.canvas.id = "pianoreplacement"+timessoundchange;
  1009.  
  1010. // [ENDMODIFIED]
  1011. ////////////////
  1012. piano.rootElement.appendChild(this.canvas);
  1013.  
  1014. Renderer.prototype.init.call(this, piano); // calls resize()
  1015.  
  1016. // create render loop
  1017. var self = this;
  1018. var render = function() {
  1019. self.redraw();
  1020. requestAnimationFrame(render);
  1021. };
  1022. requestAnimationFrame(render);
  1023.  
  1024. // add event listeners
  1025. var mouse_down = false;
  1026. var last_key = null;
  1027. $(piano.rootElement).mousedown(function(event) {
  1028. mouse_down = true;
  1029. //event.stopPropagation();
  1030. event.preventDefault();
  1031.  
  1032. var pos = CanvasRenderer.translateMouseEvent(event);
  1033. var hit = self.getHit(pos.x, pos.y);
  1034. if(hit) {
  1035. press(hit.key.note, hit.v);
  1036. last_key = hit.key;
  1037. }
  1038. });
  1039. piano.rootElement.addEventListener("touchstart", function(event) {
  1040. mouse_down = true;
  1041. //event.stopPropagation();
  1042. event.preventDefault();
  1043. for(var i in event.changedTouches) {
  1044. var pos = CanvasRenderer.translateMouseEvent(event.changedTouches[i]);
  1045. var hit = self.getHit(pos.x, pos.y);
  1046. if(hit) {
  1047. press(hit.key.note, hit.v);
  1048. last_key = hit.key;
  1049. }
  1050. }
  1051. }, false);
  1052. $(window).mouseup(function(event) {
  1053. if(last_key) {
  1054. release(last_key.note);
  1055. }
  1056. mouse_down = false;
  1057. last_key = null;
  1058. });
  1059. /*$(piano.rootElement).mousemove(function(event) {
  1060. if(!mouse_down) return;
  1061. var pos = CanvasRenderer.translateMouseEvent(event);
  1062. var hit = self.getHit(pos.x, pos.y);
  1063. if(hit && hit.key != last_key) {
  1064. press(hit.key.note, hit.v);
  1065. last_key = hit.key;
  1066. }
  1067. });*/
  1068.  
  1069. return this;
  1070. };
  1071.  
  1072. CanvasRenderer.prototype.resize = function(width, height) {
  1073. Renderer.prototype.resize.call(this, width, height);
  1074. if(this.width < 52 * 2) this.width = 52 * 2;
  1075. if(this.height < this.width * 0.2) this.height = Math.floor(this.width * 0.2);
  1076. this.canvas.width = this.width;
  1077. this.canvas.height = this.height;
  1078.  
  1079. // calculate key sizes
  1080. this.whiteKeyWidth = Math.floor(this.width / 52);
  1081. this.whiteKeyHeight = Math.floor(this.height * 0.9);
  1082. this.blackKeyWidth = Math.floor(this.whiteKeyWidth * 0.75);
  1083. this.blackKeyHeight = Math.floor(this.height * 0.5);
  1084.  
  1085. this.blackKeyOffset = Math.floor(this.whiteKeyWidth - (this.blackKeyWidth / 2));
  1086. this.keyMovement = Math.floor(this.whiteKeyHeight * 0.015);
  1087.  
  1088. this.whiteBlipWidth = Math.floor(this.whiteKeyWidth * 0.7);
  1089. this.whiteBlipHeight = Math.floor(this.whiteBlipWidth * 0.8);
  1090. this.whiteBlipX = Math.floor((this.whiteKeyWidth - this.whiteBlipWidth) / 2);
  1091. this.whiteBlipY = Math.floor(this.whiteKeyHeight - this.whiteBlipHeight * 1.2);
  1092. this.blackBlipWidth = Math.floor(this.blackKeyWidth * 0.7);
  1093. this.blackBlipHeight = Math.floor(this.blackBlipWidth * 0.8);
  1094. this.blackBlipY = Math.floor(this.blackKeyHeight - this.blackBlipHeight * 1.2);
  1095. this.blackBlipX = Math.floor((this.blackKeyWidth - this.blackBlipWidth) / 2);
  1096.  
  1097. // prerender white key
  1098. this.whiteKeyRender = document.createElement("canvas");
  1099. this.whiteKeyRender.width = this.whiteKeyWidth;
  1100. this.whiteKeyRender.height = this.height + 10;
  1101. var ctx = this.whiteKeyRender.getContext("2d");
  1102. if(ctx.createLinearGradient) {
  1103. var gradient = ctx.createLinearGradient(0, 0, 0, this.whiteKeyHeight);
  1104. gradient.addColorStop(0, "#eee");
  1105. gradient.addColorStop(0.75, "#fff");
  1106. gradient.addColorStop(1, "#dad4d4");
  1107. ctx.fillStyle = gradient;
  1108. } else {
  1109. ctx.fillStyle = "#fff";
  1110. }
  1111. ctx.strokeStyle = "#000";
  1112. ctx.lineJoin = "round";
  1113. ctx.lineCap = "round";
  1114. ctx.lineWidth = 10;
  1115. ctx.strokeRect(ctx.lineWidth / 2, ctx.lineWidth / 2, this.whiteKeyWidth - ctx.lineWidth, this.whiteKeyHeight - ctx.lineWidth);
  1116. ctx.lineWidth = 4;
  1117. ctx.fillRect(ctx.lineWidth / 2, ctx.lineWidth / 2, this.whiteKeyWidth - ctx.lineWidth, this.whiteKeyHeight - ctx.lineWidth);
  1118.  
  1119. // prerender black key
  1120. this.blackKeyRender = document.createElement("canvas");
  1121. this.blackKeyRender.width = this.blackKeyWidth + 10;
  1122. this.blackKeyRender.height = this.blackKeyHeight + 10;
  1123. var ctx = this.blackKeyRender.getContext("2d");
  1124. if(ctx.createLinearGradient) {
  1125. var gradient = ctx.createLinearGradient(0, 0, 0, this.blackKeyHeight);
  1126. gradient.addColorStop(0, "#000");
  1127. gradient.addColorStop(1, "#444");
  1128. ctx.fillStyle = gradient;
  1129. } else {
  1130. ctx.fillStyle = "#000";
  1131. }
  1132. ctx.strokeStyle = "#222";
  1133. ctx.lineJoin = "round";
  1134. ctx.lineCap = "round";
  1135. ctx.lineWidth = 8;
  1136. ctx.strokeRect(ctx.lineWidth / 2, ctx.lineWidth / 2, this.blackKeyWidth - ctx.lineWidth, this.blackKeyHeight - ctx.lineWidth);
  1137. ctx.lineWidth = 4;
  1138. ctx.fillRect(ctx.lineWidth / 2, ctx.lineWidth / 2, this.blackKeyWidth - ctx.lineWidth, this.blackKeyHeight - ctx.lineWidth);
  1139.  
  1140. // prerender shadows
  1141. this.shadowRender = [];
  1142. var y = -this.canvas.height * 2;
  1143. for(var j = 0; j < 2; j++) {
  1144. var canvas = document.createElement("canvas");
  1145. this.shadowRender[j] = canvas;
  1146. canvas.width = this.canvas.width;
  1147. canvas.height = this.canvas.height;
  1148. var ctx = canvas.getContext("2d");
  1149. var sharp = j ? true : false;
  1150. ctx.lineJoin = "round";
  1151. ctx.lineCap = "round";
  1152. ctx.lineWidth = 1;
  1153. ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
  1154. ctx.shadowBlur = this.keyMovement * 3;
  1155. ctx.shadowOffsetY = -y + this.keyMovement;
  1156. if(sharp) {
  1157. ctx.shadowOffsetX = this.keyMovement;
  1158. } else {
  1159. ctx.shadowOffsetX = 0;
  1160. ctx.shadowOffsetY = -y + this.keyMovement;
  1161. }
  1162. for(var i in this.piano.keys) {
  1163. if(!this.piano.keys.hasOwnProperty(i)) continue;
  1164. var key = this.piano.keys[i];
  1165. if(key.sharp != sharp) continue;
  1166.  
  1167. if(key.sharp) {
  1168. ctx.fillRect(this.blackKeyOffset + this.whiteKeyWidth * key.spatial + ctx.lineWidth / 2,
  1169. y + ctx.lineWidth / 2,
  1170. this.blackKeyWidth - ctx.lineWidth, this.blackKeyHeight - ctx.lineWidth);
  1171. } else {
  1172. ctx.fillRect(this.whiteKeyWidth * key.spatial + ctx.lineWidth / 2,
  1173. y + ctx.lineWidth / 2,
  1174. this.whiteKeyWidth - ctx.lineWidth, this.whiteKeyHeight - ctx.lineWidth);
  1175. }
  1176. }
  1177. }
  1178.  
  1179. // update key rects
  1180. for(var i in this.piano.keys) {
  1181. if(!this.piano.keys.hasOwnProperty(i)) continue;
  1182. var key = this.piano.keys[i];
  1183. if(key.sharp) {
  1184. key.rect = new Rect(this.blackKeyOffset + this.whiteKeyWidth * key.spatial, 0,
  1185. this.blackKeyWidth, this.blackKeyHeight);
  1186. } else {
  1187. key.rect = new Rect(this.whiteKeyWidth * key.spatial, 0,
  1188. this.whiteKeyWidth, this.whiteKeyHeight);
  1189. }
  1190. }
  1191. };
  1192.  
  1193. CanvasRenderer.prototype.visualize = function(key, color) {
  1194. key.timePlayed = Date.now();
  1195. key.blips.push({"time": key.timePlayed, "color": color});
  1196. };
  1197.  
  1198. CanvasRenderer.prototype.redraw = function() {
  1199. var now = Date.now();
  1200. var timeLoadedEnd = now - 1000;
  1201. var timePlayedEnd = now - 100;
  1202. var timeBlipEnd = now - 1000;
  1203.  
  1204. this.ctx.save();
  1205. this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  1206. // draw all keys
  1207. for(var j = 0; j < 2; j++) {
  1208. this.ctx.globalAlpha = 1.0;
  1209. this.ctx.drawImage(this.shadowRender[j], 0, 0);
  1210. var sharp = j ? true : false;
  1211. for(var i in this.piano.keys) {
  1212. if(!this.piano.keys.hasOwnProperty(i)) continue;
  1213. var key = this.piano.keys[i];
  1214. if(key.sharp != sharp) continue;
  1215.  
  1216. if(!key.loaded) {
  1217. this.ctx.globalAlpha = 0.2;
  1218. } else if(key.timeLoaded > timeLoadedEnd) {
  1219. this.ctx.globalAlpha = ((now - key.timeLoaded) / 1000) * 0.8 + 0.2;
  1220. } else {
  1221. this.ctx.globalAlpha = 1.0;
  1222. }
  1223. var y = 0;
  1224. if(key.timePlayed > timePlayedEnd) {
  1225. y = Math.floor(this.keyMovement - (((now - key.timePlayed) / 100) * this.keyMovement));
  1226. }
  1227. var x = Math.floor(key.sharp ? this.blackKeyOffset + this.whiteKeyWidth * key.spatial
  1228. : this.whiteKeyWidth * key.spatial);
  1229. var image = key.sharp ? this.blackKeyRender : this.whiteKeyRender;
  1230. this.ctx.drawImage(image, x, y);
  1231.  
  1232. // render blips
  1233. if(key.blips.length) {
  1234. var alpha = this.ctx.globalAlpha;
  1235. var w, h;
  1236. if(key.sharp) {
  1237. x += this.blackBlipX;
  1238. y = this.blackBlipY;
  1239. w = this.blackBlipWidth;
  1240. h = this.blackBlipHeight;
  1241. } else {
  1242. x += this.whiteBlipX;
  1243. y = this.whiteBlipY;
  1244. w = this.whiteBlipWidth;
  1245. h = this.whiteBlipHeight;
  1246. }
  1247. for(var b = 0; b < key.blips.length; b++) {
  1248. var blip = key.blips[b];
  1249. if(blip.time > timeBlipEnd) {
  1250. this.ctx.fillStyle = blip.color;
  1251. this.ctx.globalAlpha = alpha - ((now - blip.time) / 1000);
  1252. this.ctx.fillRect(x, y, w, h);
  1253. } else {
  1254. key.blips.splice(b, 1);
  1255. --b;
  1256. }
  1257. y -= Math.floor(h * 1.1);
  1258. }
  1259. }
  1260. }
  1261. }
  1262. this.ctx.restore();
  1263. };
  1264.  
  1265. CanvasRenderer.prototype.getHit = function(x, y) {
  1266. for(var j = 0; j < 2; j++) {
  1267. var sharp = j ? false : true; // black keys first
  1268. for(var i in this.piano.keys) {
  1269. if(!this.piano.keys.hasOwnProperty(i)) continue;
  1270. var key = this.piano.keys[i];
  1271. if(key.sharp != sharp) continue;
  1272. if(key.rect.contains(x, y)) {
  1273. var v = y / (key.sharp ? this.blackKeyHeight : this.whiteKeyHeight);
  1274. v += 0.25;
  1275. v *= DEFAULT_VELOCITY;
  1276. if(v > 1.0) v = 1.0;
  1277. return {"key": key, "v": v};
  1278. }
  1279. }
  1280. }
  1281. return null;
  1282. };
  1283.  
  1284.  
  1285. CanvasRenderer.isSupported = function() {
  1286. var canvas = document.createElement("canvas");
  1287. return !!(canvas.getContext && canvas.getContext("2d"));
  1288. };
  1289.  
  1290. CanvasRenderer.translateMouseEvent = function(evt) {
  1291. var element = evt.target;
  1292. var offx = 0;
  1293. var offy = 0;
  1294. do {
  1295. if(!element) break; // wtf, wtf?
  1296. offx += element.offsetLeft;
  1297. offy += element.offsetTop;
  1298. } while(element = element.offsetParent);
  1299. return {
  1300. x: evt.pageX - offx,
  1301. y: evt.pageY - offy
  1302. }
  1303. };
  1304.  
  1305.  
  1306.  
  1307.  
  1308.  
  1309.  
  1310.  
  1311.  
  1312.  
  1313.  
  1314.  
  1315.  
  1316. // Pianoctor
  1317.  
  1318. ////////////////////////////////////////////////////////////////
  1319.  
  1320. var PianoKey = function(note, octave) {
  1321. this.note = note + octave;
  1322. this.baseNote = note;
  1323. this.octave = octave;
  1324. this.sharp = note.indexOf("s") != -1;
  1325. this.loaded = false;
  1326. this.timeLoaded = 0;
  1327. this.domElement = null;
  1328. this.timePlayed = 0;
  1329. this.blips = [];
  1330. };
  1331.  
  1332. var Piano = function(rootElement) {
  1333.  
  1334. var piano = this;
  1335. piano.rootElement = rootElement;
  1336. piano.keys = {};
  1337.  
  1338. var white_spatial = 0;
  1339. var black_spatial = 0;
  1340. var black_it = 0;
  1341. var black_lut = [2, 1, 2, 1, 1];
  1342. var addKey = function(note, octave) {
  1343. var key = new PianoKey(note, octave);
  1344. piano.keys[key.note] = key;
  1345. if(key.sharp) {
  1346. key.spatial = black_spatial;
  1347. black_spatial += black_lut[black_it % 5];
  1348. ++black_it;
  1349. } else {
  1350. key.spatial = white_spatial;
  1351. ++white_spatial;
  1352. }
  1353. }
  1354. if(test_mode) {
  1355. addKey("c", 2);
  1356. } else {
  1357. addKey("a", -1);
  1358. addKey("as", -1);
  1359. addKey("b", -1);
  1360. var notes = "c cs d ds e f fs g gs a as b".split(" ");
  1361. for(var oct = 0; oct < 7; oct++) {
  1362. for(var i in notes) {
  1363. addKey(notes[i], oct);
  1364. }
  1365. }
  1366. addKey("c", 7);
  1367. }
  1368.  
  1369.  
  1370. var render_engine = CanvasRenderer.isSupported() ? CanvasRenderer : DOMRenderer;
  1371. this.renderer = new render_engine().init(this);
  1372.  
  1373. window.addEventListener("resize", function() {
  1374. piano.renderer.resize();
  1375. });
  1376.  
  1377.  
  1378. window.AudioContext = window.AudioContext || window.webkitAudioContext || undefined;
  1379. var audio_engine = AudioEngineWeb;
  1380.  
  1381. this.audio = new audio_engine().init(function() {
  1382. for(var i in piano.keys) {
  1383. if(!piano.keys.hasOwnProperty(i)) continue;
  1384. (function() {
  1385. var key = piano.keys[i];
  1386. piano.audio.load(key.note, gSoundPath + key.note + gSoundExt, function() {
  1387. key.loaded = true;
  1388. key.timeLoaded = Date.now();
  1389. if(key.domElement) // todo: move this to renderer somehow
  1390. $(key.domElement).removeClass("loading");
  1391. });
  1392. })();
  1393. }
  1394. });
  1395. };
  1396.  
  1397. Piano.prototype.play = function(note, vol, participant, delay_ms) {
  1398. if(!this.keys.hasOwnProperty(note)) return;
  1399. var key = this.keys[note];
  1400. if(key.loaded) this.audio.play(key.note, vol, delay_ms, participant.id);
  1401. if(typeof gMidiOutTest === "function") gMidiOutTest(key.note, vol * 100, delay_ms);
  1402. var self = this;
  1403. var jq_namediv = $(typeof participant == "undefined" ? null : participant.nameDiv);
  1404. if(jq_namediv) {
  1405. setTimeout(function() {
  1406. self.renderer.visualize(key, typeof participant == "undefined" ? "yellow" : (participant.color || "#777"));
  1407. jq_namediv.addClass("play");
  1408. setTimeout(function() {
  1409. jq_namediv.removeClass("play");
  1410. }, 30);
  1411. }, delay_ms);
  1412. }
  1413. };
  1414.  
  1415. Piano.prototype.stop = function(note, participant, delay_ms) {
  1416. if(!this.keys.hasOwnProperty(note)) return;
  1417. var key = this.keys[note];
  1418. if(key.loaded) this.audio.stop(key.note, delay_ms, participant.id);
  1419. if(typeof gMidiOutTest === "function") gMidiOutTest(key.note, 0, delay_ms);
  1420. };
  1421.  
  1422. var gPiano = new Piano(document.getElementById("piano"));
  1423.  
  1424.  
  1425.  
  1426.  
  1427.  
  1428.  
  1429.  
  1430. var gAutoSustain = true; //!(window.location.hash && window.location.hash.match(/^(?:#.+)*#sustain(?:#.+)*$/));
  1431. var gSustain = false;
  1432.  
  1433. var gHeldNotes = {};
  1434. var gSustainedNotes = {};
  1435.  
  1436.  
  1437. function press(id, vol) {
  1438. if(!gClient.preventsPlaying() && gNoteQuota.spend(1)) {
  1439. gHeldNotes[id] = true;
  1440. gSustainedNotes[id] = true;
  1441. gPiano.play(id, vol !== undefined ? vol : DEFAULT_VELOCITY, gClient.getOwnParticipant(), 0);
  1442. gClient.startNote(id, vol);
  1443. }
  1444. }
  1445.  
  1446. function release(id) {
  1447. if(gHeldNotes[id]) {
  1448. gHeldNotes[id] = false;
  1449. if((gAutoSustain || gSustain) && !enableSynth) {
  1450. gSustainedNotes[id] = true;
  1451. } else {
  1452. if(gNoteQuota.spend(1)) {
  1453. gPiano.stop(id, gClient.getOwnParticipant(), 0);
  1454. gClient.stopNote(id);
  1455. gSustainedNotes[id] = false;
  1456. }
  1457. }
  1458. }
  1459. }
  1460.  
  1461. function pressSustain() {
  1462. gSustain = true;
  1463. }
  1464.  
  1465. function releaseSustain() {
  1466. gSustain = false;
  1467. if(!gAutoSustain) {
  1468. for(var id in gSustainedNotes) {
  1469. if(gSustainedNotes.hasOwnProperty(id) && gSustainedNotes[id] && !gHeldNotes[id]) {
  1470. gSustainedNotes[id] = false;
  1471. if(gNoteQuota.spend(1)) {
  1472. gPiano.stop(id, gClient.getOwnParticipant(), 0);
  1473. gClient.stopNote(id);
  1474. }
  1475. }
  1476. }
  1477. }
  1478. }
  1479.  
  1480.  
  1481.  
  1482.  
  1483.  
  1484.  
  1485.  
  1486.  
  1487.  
  1488. // internet science
  1489.  
  1490. ////////////////////////////////////////////////////////////////
  1491.  
  1492. var channel_id = decodeURIComponent(window.location.pathname);
  1493. if(channel_id.substr(0, 1) == "/") channel_id = channel_id.substr(1);
  1494. if(channel_id == "") channel_id = "lobby";
  1495.  
  1496. var wssport = window.location.hostname == "www.multiplayerpiano.com" ? 443 : 8080;
  1497. var gClient = new Client("ws://" + window.location.hostname + ":" + wssport);
  1498. gClient.setChannel(channel_id);
  1499. gClient.start();
  1500.  
  1501.  
  1502. // Setting status
  1503. (function() {
  1504. gClient.on("status", function(status) {
  1505. $("#status").text(status);
  1506. });
  1507. gClient.on("count", function(count) {
  1508. if(count > 0) {
  1509. $("#status").html('<span class="number">'+count+'</span> '+(count==1? 'person is' : 'people are')+' playing');
  1510. document.title = "Piano (" + count + ")";
  1511. } else {
  1512. document.title = "Multiplayer Piano";
  1513. }
  1514. });
  1515. })();
  1516.  
  1517. // Handle changes to participants
  1518. (function() {
  1519. gClient.on("participant added", function(part) {
  1520.  
  1521. part.displayX = 150;
  1522. part.displayY = 50;
  1523.  
  1524. // add nameDiv
  1525. var div = document.createElement("div");
  1526. div.className = "name";
  1527. div.participantId = part.id;
  1528. div.textContent = part.name || "";
  1529. div.style.backgroundColor = part.color || "#fff";
  1530. if(gClient.participantId === part.id) {
  1531. $(div).addClass("me");
  1532. }
  1533. if(gClient.channel && gClient.channel.crown && gClient.channel.crown.participantId === part.id) {
  1534. $(div).addClass("owner");
  1535. }
  1536. if(gPianoMutes.indexOf(part._id) !== -1) {
  1537. $(part.nameDiv).addClass("muted-notes");
  1538. }
  1539. if(gChatMutes.indexOf(part._id) !== -1) {
  1540. $(part.nameDiv).addClass("muted-chat");
  1541. }
  1542. div.style.display = "none";
  1543. part.nameDiv = $("#names")[0].appendChild(div);
  1544. $(part.nameDiv).fadeIn(2000);
  1545.  
  1546. // sort names
  1547. var arr = $("#names .name");
  1548. arr.sort(function(a, b) {
  1549. a = a.style.backgroundColor; // todo: sort based on user id instead
  1550. b = b.style.backgroundColor;
  1551. if (a > b) return 1;
  1552. else if (a < b) return -1;
  1553. else return 0;
  1554. });
  1555. $("#names").html(arr);
  1556.  
  1557. // add cursorDiv
  1558. if(gClient.participantId !== part.id || gSeeOwnCursor) {
  1559. var div = document.createElement("div");
  1560. div.className = "cursor";
  1561. div.style.display = "none";
  1562. part.cursorDiv = $("#cursors")[0].appendChild(div);
  1563. $(part.cursorDiv).fadeIn(2000);
  1564.  
  1565. var div = document.createElement("div");
  1566. div.className = "name";
  1567. div.style.backgroundColor = part.color || "#fff"
  1568. div.textContent = part.name || "";
  1569. part.cursorDiv.appendChild(div);
  1570.  
  1571. } else {
  1572. part.cursorDiv = undefined;
  1573. }
  1574. });
  1575. gClient.on("participant removed", function(part) {
  1576. // remove nameDiv
  1577. var nd = $(part.nameDiv);
  1578. var cd = $(part.cursorDiv);
  1579. cd.fadeOut(2000);
  1580. nd.fadeOut(2000, function() {
  1581. nd.remove();
  1582. cd.remove();
  1583. part.nameDiv = undefined;
  1584. part.cursorDiv = undefined;
  1585. });
  1586. });
  1587. gClient.on("participant update", function(part) {
  1588. var name = part.name || "";
  1589. var color = part.color || "#fff";
  1590. part.nameDiv.style.backgroundColor = color;
  1591. part.nameDiv.textContent = name;
  1592. $(part.cursorDiv)
  1593. .find(".name")
  1594. .text(name)
  1595. .css("background-color", color);
  1596. });
  1597. gClient.on("ch", function(msg) {
  1598. for(var id in gClient.ppl) {
  1599. if(gClient.ppl.hasOwnProperty(id)) {
  1600. var part = gClient.ppl[id];
  1601. if(part.id === gClient.participantId) {
  1602. $(part.nameDiv).addClass("me");
  1603. } else {
  1604. $(part.nameDiv).removeClass("me");
  1605. }
  1606. if(msg.ch.crown && msg.ch.crown.participantId === part.id) {
  1607. $(part.nameDiv).addClass("owner");
  1608. $(part.cursorDiv).addClass("owner");
  1609. } else {
  1610. $(part.nameDiv).removeClass("owner");
  1611. $(part.cursorDiv).removeClass("owner");
  1612. }
  1613. if(gPianoMutes.indexOf(part._id) !== -1) {
  1614. $(part.nameDiv).addClass("muted-notes");
  1615. } else {
  1616. $(part.nameDiv).removeClass("muted-notes");
  1617. }
  1618. if(gChatMutes.indexOf(part._id) !== -1) {
  1619. $(part.nameDiv).addClass("muted-chat");
  1620. } else {
  1621. $(part.nameDiv).removeClass("muted-chat");
  1622. }
  1623. }
  1624. }
  1625. });
  1626. })();
  1627.  
  1628.  
  1629. // Handle changes to crown
  1630. (function() {
  1631. var jqcrown = $('<div id="crown"></div>').appendTo(document.body).hide();
  1632. var jqcountdown = $('<span></span>').appendTo(jqcrown);
  1633. var countdown_interval;
  1634. jqcrown.click(function() {
  1635. gClient.sendArray([{m: "chown", id: gClient.participantId}]);
  1636. });
  1637. gClient.on("ch", function(msg) {
  1638. if(msg.ch.crown) {
  1639. var crown = msg.ch.crown;
  1640. if(!crown.participantId || !gClient.ppl[crown.participantId]) {
  1641. var land_time = crown.time + 2000 - gClient.serverTimeOffset;
  1642. var avail_time = crown.time + 15000 - gClient.serverTimeOffset;
  1643. jqcountdown.text("");
  1644. jqcrown.show();
  1645. if(land_time - Date.now() <= 0) {
  1646. jqcrown.css({"left": crown.endPos.x + "%", "top": crown.endPos.y + "%"});
  1647. } else {
  1648. jqcrown.css({"left": crown.startPos.x + "%", "top": crown.startPos.y + "%"});
  1649. jqcrown.addClass("spin");
  1650. jqcrown.animate({"left": crown.endPos.x + "%", "top": crown.endPos.y + "%"}, 2000, "linear", function() {
  1651. jqcrown.removeClass("spin");
  1652. });
  1653. }
  1654. clearInterval(countdown_interval);
  1655. countdown_interval = setInterval(function() {
  1656. var time = Date.now();
  1657. if(time >= land_time) {
  1658. var ms = avail_time - time;
  1659. if(ms > 0) {
  1660. jqcountdown.text(Math.ceil(ms / 1000) + "s");
  1661. } else {
  1662. jqcountdown.text("");
  1663. clearInterval(countdown_interval);
  1664. }
  1665. }
  1666. }, 1000);
  1667. } else {
  1668. jqcrown.hide();
  1669. }
  1670. } else {
  1671. jqcrown.hide();
  1672. }
  1673. });
  1674. gClient.on("disconnect", function() {
  1675. jqcrown.fadeOut(2000);
  1676. });
  1677. })();
  1678.  
  1679.  
  1680. // Playing notes
  1681. gClient.on("n", function(msg) {
  1682. var t = msg.t - gClient.serverTimeOffset + TIMING_TARGET - Date.now();
  1683. var participant = gClient.findParticipantById(msg.p);
  1684. if(gPianoMutes.indexOf(participant._id) !== -1)
  1685. return;
  1686. for(var i = 0; i < msg.n.length; i++) {
  1687. var note = msg.n[i];
  1688. var ms = t + (note.d || 0);
  1689. if(ms < 0) {
  1690. ms = 0;
  1691. }
  1692. else if(ms > 10000) continue;
  1693. if(note.s) {
  1694. gPiano.stop(note.n, participant, ms);
  1695. } else {
  1696. var vel = (typeof note.v !== "undefined")? parseFloat(note.v) : DEFAULT_VELOCITY;
  1697. if(vel < 0) vel = 0; else if (vel > 1) vel = 1;
  1698. gPiano.play(note.n, vel, participant, ms);
  1699. if(enableSynth) {
  1700. gPiano.stop(note.n, participant, ms + 1000);
  1701. }
  1702. }
  1703. }
  1704. });
  1705.  
  1706. // Send cursor updates
  1707. var mx = 0, last_mx = -10, my = 0, last_my = -10;
  1708. setInterval(function() {
  1709. if(Math.abs(mx - last_mx) > 0.1 || Math.abs(my - last_my) > 0.1) {
  1710. last_mx = mx;
  1711. last_my = my;
  1712. gClient.sendArray([{m: "m", x: mx, y: my}]);
  1713. var part = gClient.getOwnParticipant();
  1714. if(part) {
  1715. part.x = mx;
  1716. part.y = my;
  1717. }
  1718. }
  1719. }, 50);
  1720. $(document).mousemove(function(event) {
  1721. mx = ((event.pageX / $(window).width()) * 100).toFixed(2);
  1722. my = ((event.pageY / $(window).height()) * 100).toFixed(2);
  1723. });
  1724.  
  1725. // Animate cursors
  1726. setInterval(function() {
  1727. for(var id in gClient.ppl) {
  1728. if(!gClient.ppl.hasOwnProperty(id)) continue;
  1729. var part = gClient.ppl[id];
  1730. if(part.cursorDiv && (Math.abs(part.x - part.displayX) > 0.1 || Math.abs(part.y - part.displayY) > 0.1)) {
  1731. part.displayX += (part.x - part.displayX) * 0.75;
  1732. part.displayY += (part.y - part.displayY) * 0.75;
  1733. part.cursorDiv.style.left = part.displayX + "%";
  1734. part.cursorDiv.style.top = part.displayY + "%";
  1735. }
  1736. }
  1737. }, 50);
  1738.  
  1739.  
  1740. // Room settings button
  1741. (function() {
  1742. gClient.on("ch", function(msg) {
  1743. if(gClient.isOwner()) {
  1744. $("#room-settings-btn").show();
  1745. } else {
  1746. $("#room-settings-btn").hide();
  1747. }
  1748. });
  1749. $("#room-settings-btn").click(function(evt) {
  1750. if(gClient.channel && gClient.isOwner()) {
  1751. var settings = gClient.channel.settings;
  1752. openModal("#room-settings");
  1753. setTimeout(function() {
  1754. $("#room-settings .checkbox[name=visible]").prop("checked", settings.visible);
  1755. $("#room-settings .checkbox[name=chat]").prop("checked", settings.chat);
  1756. $("#room-settings .checkbox[name=crownsolo]").prop("checked", settings.crownsolo);
  1757. $("#room-settings input[name=color]").val(settings.color);
  1758. }, 100);
  1759. }
  1760. });
  1761. $("#room-settings .submit").click(function() {
  1762. var settings = {
  1763. visible: $("#room-settings .checkbox[name=visible]").is(":checked"),
  1764. chat: $("#room-settings .checkbox[name=chat]").is(":checked"),
  1765. crownsolo: $("#room-settings .checkbox[name=crownsolo]").is(":checked"),
  1766. color: $("#room-settings input[name=color]").val()
  1767. };
  1768. gClient.sendArray([{m: "chset", set: settings}]);
  1769. closeModal();
  1770. });
  1771. $("#room-settings .drop-crown").click(function() {
  1772. gClient.sendArray([{m: "chown"}]);
  1773. closeModal();
  1774. });
  1775. })();
  1776.  
  1777. // Handle notifications
  1778. gClient.on("notification", function(msg) {
  1779. new Notification(msg);
  1780. });
  1781.  
  1782. // Don't foget spin
  1783. gClient.on("ch", function(msg) {
  1784. var chidlo = msg.ch._id.toLowerCase();
  1785. if(chidlo === "spin" || chidlo.substr(-5) === "/spin") {
  1786. $("#piano").addClass("spin");
  1787. } else {
  1788. $("#piano").removeClass("spin");
  1789. }
  1790. });
  1791.  
  1792. /*function eb() {
  1793. if(gClient.channel && gClient.channel._id.toLowerCase() === "test/fishing") {
  1794. ebsprite.start(gClient);
  1795. } else {
  1796. ebsprite.stop();
  1797. }
  1798. }
  1799. if(ebsprite) {
  1800. gClient.on("ch", eb);
  1801. eb();
  1802. }*/
  1803.  
  1804. // Crownsolo notice
  1805. gClient.on("ch", function(msg) {
  1806. if(msg.ch.settings.crownsolo) {
  1807. if($("#crownsolo-notice").length == 0) {
  1808. $('<div id="crownsolo-notice">').text('This room is set to "only the owner can play."').appendTo("body").fadeIn(1000);
  1809. }
  1810. } else {
  1811. $("#crownsolo-notice").remove();
  1812. }
  1813. });
  1814. gClient.on("disconnect", function() {
  1815. $("#crownsolo-notice").remove();
  1816. });
  1817.  
  1818.  
  1819. // Background color
  1820. (function() {
  1821. var old_color1 = new Color("#3b5054");
  1822. var old_color2 = new Color("#3b5054");
  1823. function setColor(hex) {
  1824. var color1 = new Color(hex);
  1825. var color2 = new Color(hex);
  1826. color2.add(-0x40, -0x40, -0x40);
  1827.  
  1828. var bottom = document.getElementById("bottom");
  1829.  
  1830. var duration = 500;
  1831. var step = 0;
  1832. var steps = 30;
  1833. var step_ms = duration / steps;
  1834. var difference = new Color(color1.r, color1.g, color1.b);
  1835. difference.r -= old_color1.r;
  1836. difference.g -= old_color1.g;
  1837. difference.b -= old_color1.b;
  1838. var inc = new Color(difference.r / steps, difference.g / steps, difference.b / steps);
  1839. var iv;
  1840. iv = setInterval(function() {
  1841. old_color1.add(inc.r, inc.g, inc.b);
  1842. old_color2.add(inc.r, inc.g, inc.b);
  1843. document.body.style.background = "radial-gradient(ellipse at center, "+old_color1.toHexa()+" 0%,"+old_color2.toHexa()+" 100%)";
  1844. bottom.style.background = old_color2.toHexa();
  1845. if(++step >= steps) {
  1846. clearInterval(iv);
  1847. old_color1 = color1;
  1848. old_color2 = color2;
  1849. document.body.style.background = "radial-gradient(ellipse at center, "+color1.toHexa()+" 0%,"+color2.toHexa()+" 100%)";
  1850. bottom.style.background = color2.toHexa();
  1851. }
  1852. }, step_ms);
  1853. }
  1854.  
  1855. setColor("#000000");
  1856.  
  1857. gClient.on("ch", function(ch) {
  1858. if(ch.ch.settings) {
  1859. if(ch.ch.settings.color) {
  1860. setColor(ch.ch.settings.color);
  1861. } else {
  1862. setColor("#3b5054");
  1863. }
  1864. }
  1865. });
  1866. })();
  1867.  
  1868.  
  1869.  
  1870.  
  1871.  
  1872.  
  1873. var gPianoMutes = [];
  1874.  
  1875. var gChatMutes = [];
  1876.  
  1877.  
  1878.  
  1879.  
  1880.  
  1881.  
  1882.  
  1883.  
  1884.  
  1885.  
  1886.  
  1887.  
  1888.  
  1889.  
  1890.  
  1891.  
  1892.  
  1893.  
  1894.  
  1895. var volume_slider = new VolumeSlider(document.getElementById("volume"), function(v) {
  1896. gPiano.audio.setVolume(v);
  1897. if(window.localStorage) localStorage.volume = v;
  1898. });
  1899. volume_slider.set(gPiano.audio.volume);
  1900.  
  1901. var Note = function(note, octave) {
  1902. this.note = note;
  1903. this.octave = octave || 0;
  1904. };
  1905.  
  1906.  
  1907.  
  1908. var n = function(a, b) { return {note: new Note(a, b), held: false}; };
  1909.  
  1910. // [MODIFIED]
  1911. // custom key bindings
  1912. //////////////////////
  1913.  
  1914. var key_binding = {
  1915. // left, right
  1916. // f1-f7 for lower notes
  1917. 37: n("a", -2),
  1918. 39: n("b", -2),
  1919. 112: n("c", -1),
  1920. 113: n("d", -1),
  1921. 114: n("e", -1),
  1922. 115: n("f", -1),
  1923. 116: n("g", -1),
  1924. 117: n("a", -1),
  1925. 118: n("b", -1),
  1926.  
  1927. //insert - home - pgup - del - end - pgdn - up for highest
  1928. 45: n("d", 5),
  1929. 36: n("e", 5),
  1930. 33: n("f", 5),
  1931. 46: n("g", 5),
  1932. 35: n("a", 5),
  1933. 34: n("b", 5),
  1934. 38: n("c", 6),
  1935.  
  1936. // alphanumerics 1-m
  1937. 49: n("c"),
  1938. 50: n("d"),
  1939. 51: n("e"),
  1940. 52: n("f"),
  1941. 53: n("g"),
  1942. 54: n("a"),
  1943. 55: n("b"),
  1944. 56: n("c", 1),
  1945. 57: n("d", 1),
  1946. 48: n("e", 1),
  1947. 81: n("f", 1),
  1948. 87: n("g", 1),
  1949. 69: n("a", 1),
  1950. 82: n("b", 1),
  1951. 84: n("c", 2),
  1952. 89: n("d", 2),
  1953. 85: n("e", 2),
  1954. 73: n("f", 2),
  1955. 79: n("g", 2),
  1956. 80: n("a", 2),
  1957. 65: n("b", 2),
  1958. 83: n("c", 3),
  1959. 68: n("d", 3),
  1960. 70: n("e", 3),
  1961. 71: n("f", 3),
  1962. 72: n("g", 3),
  1963. 74: n("a", 3),
  1964. 75: n("b", 3),
  1965. 76: n("c", 4),
  1966. 90: n("d", 4),
  1967. 88: n("e", 4),
  1968. 67: n("f", 4),
  1969. 86: n("g", 4),
  1970. 66: n("a", 4),
  1971. 78: n("b", 4),
  1972. 77: n("c", 5)
  1973. };
  1974.  
  1975. // [ENDMODIFIED]
  1976. ////////////////
  1977.  
  1978. var capsLockKey = false;
  1979.  
  1980. var transpose_octave = 0;
  1981.  
  1982. // [MODIFIED]
  1983. // new key handling logic
  1984. /////////////////////////
  1985.  
  1986. var additional_octaves = 0; // number of additional octaves to play at same time
  1987. var transpose_halfsteps = 0; // number of half steps to increase note by
  1988. var transpose_array = ["c","cs","d","ds","e","f","fs","g","gs","a","as","b"];
  1989.  
  1990. function handleKeyDown(evt) {
  1991. //console.log(evt);
  1992. var code = parseInt(evt.keyCode);
  1993. if(key_binding[code] !== undefined) {
  1994. var binding = key_binding[code];
  1995. if(!binding.held) {
  1996. binding.held = true;
  1997.  
  1998. var note = binding.note; // the note ie c cs d ds
  1999. var octave = 1 + note.octave + transpose_octave; // the octave (a number)
  2000.  
  2001. if(evt.shiftKey) note = note.note + "s";
  2002. else note = note.note;
  2003.  
  2004. if (note === "bs") note = "c", octave++;
  2005. else if (note === "es")note = "f";
  2006.  
  2007. // if the transpose halfsteps is negative and greater than the index of the note then treat as going positive by 12 plus the negative but octave goes down once
  2008. // because of adding 12
  2009. var c_o_octave_mod = 0;
  2010. var new_note_index = (transpose_array.indexOf(note) + transpose_halfsteps)
  2011. if (transpose_array.indexOf(note) < -transpose_halfsteps) {
  2012. c_o_octave_mod = -1;
  2013. new_note_index = (transpose_array.indexOf(note) + transpose_halfsteps + 12)
  2014. }
  2015. note = transpose_array[new_note_index % 12];
  2016. var carry_over_octave = Math.floor(new_note_index / 12); // if theres overlap then increase the octave
  2017. octave += carry_over_octave + c_o_octave_mod;
  2018.  
  2019. var add_oct_mult = 1;
  2020. if(additional_octaves < 0) add_oct_mult = -1;
  2021. for(var add_oct = 0; add_oct <= Math.abs(additional_octaves); add_oct++) {
  2022. var note1 = note + (octave + add_oct * add_oct_mult);
  2023. var vol = velocityFromMouseY();
  2024. //console.log(note1);
  2025. press(note1, vol);
  2026. }
  2027. }
  2028.  
  2029. // [ENDMODIFIED]
  2030. ////////////////
  2031.  
  2032. if(++gKeyboardSeq == 3) {
  2033. gKnowsYouCanUseKeyboard = true;
  2034. if(window.gKnowsYouCanUseKeyboardTimeout) clearTimeout(gKnowsYouCanUseKeyboardTimeout);
  2035. if(localStorage) localStorage.knowsYouCanUseKeyboard = true;
  2036. if(window.gKnowsYouCanUseKeyboardNotification) gKnowsYouCanUseKeyboardNotification.close();
  2037. }
  2038.  
  2039. evt.preventDefault();
  2040. evt.stopPropagation();
  2041. return false;
  2042. } else if(code == 20) { // Caps Lock
  2043. capsLockKey = true;
  2044. evt.preventDefault();
  2045. } else if(code === 0x20) { // Space Bar
  2046. pressSustain();
  2047. evt.preventDefault();
  2048. } else if((code === 38 || code === 39) && transpose_octave < 3) {
  2049. ++transpose_octave;
  2050. } else if((code === 40 || code === 37) && transpose_octave > -2) {
  2051. --transpose_octave;
  2052. } else if(code == 9) { // Tab (don't tab away from the piano)
  2053. evt.preventDefault();
  2054. } else if(code == 8) { // Backspace (don't navigate Back)
  2055. gAutoSustain = !gAutoSustain;
  2056. evt.preventDefault();
  2057. }
  2058. };
  2059.  
  2060. function handleKeyUp(evt) {
  2061. var code = parseInt(evt.keyCode);
  2062. if(key_binding[code] !== undefined) {
  2063. var binding = key_binding[code];
  2064. if(binding.held) {
  2065. binding.held = false;
  2066.  
  2067. var note = binding.note;
  2068. var octave = 1 + note.octave + transpose_octave;
  2069. if(evt.shiftKey) ++octave;
  2070. else if(capsLockKey || evt.ctrlKey) --octave;
  2071. note = note.note + octave;
  2072. release(note);
  2073. }
  2074.  
  2075. evt.preventDefault();
  2076. evt.stopPropagation();
  2077. return false;
  2078. } else if(code == 20) { // Caps Lock
  2079. capsLockKey = false;
  2080. evt.preventDefault();
  2081. } else if(code === 0x20) { // Space Bar
  2082. releaseSustain();
  2083. evt.preventDefault();
  2084. }
  2085. };
  2086.  
  2087. function handleKeyPress(evt) {
  2088. evt.preventDefault();
  2089. evt.stopPropagation();
  2090. if(evt.keyCode == 27 || evt.keyCode == 13) {
  2091. //$("#chat input").focus();
  2092. }
  2093. return false;
  2094. };
  2095.  
  2096. var recapListener = function(evt) {
  2097. captureKeyboard();
  2098. };
  2099.  
  2100. function captureKeyboard() {
  2101. $("#piano").off("mousedown", recapListener);
  2102. $("#piano").off("touchstart", recapListener);
  2103. $(document).on("keydown", handleKeyDown );
  2104. $(document).on("keyup", handleKeyUp);
  2105. $(window).on("keypress", handleKeyPress );
  2106. };
  2107.  
  2108. function releaseKeyboard() {
  2109. $(document).off("keydown", handleKeyDown );
  2110. $(document).off("keyup", handleKeyUp);
  2111. $(window).off("keypress", handleKeyPress );
  2112. $("#piano").on("mousedown", recapListener);
  2113. $("#piano").on("touchstart", recapListener);
  2114. };
  2115.  
  2116. captureKeyboard();
  2117.  
  2118.  
  2119. var velocityFromMouseY = function() {
  2120. return 0.1 + (my / 100) * 0.6;
  2121. };
  2122.  
  2123.  
  2124.  
  2125.  
  2126.  
  2127. // NoteQuota
  2128. var gNoteQuota = (function() {
  2129. var last_rat = 0;
  2130. var nqjq = $("#quota .value");
  2131. setInterval(function() {
  2132. gNoteQuota.tick();
  2133. }, 2000);
  2134. return new NoteQuota(function(points) {
  2135. // update UI
  2136. var rat = (points / this.max) * 100;
  2137. if(rat <= last_rat)
  2138. nqjq.stop(true, true).css("width", rat.toFixed(0) + "%");
  2139. else
  2140. nqjq.stop(true, true).animate({"width": rat.toFixed(0) + "%"}, 2000, "linear");
  2141. last_rat = rat;
  2142. });
  2143. })();
  2144. gClient.on("nq", function(nq_params) {
  2145. gNoteQuota.setParams(nq_params);
  2146. });
  2147. gClient.on("disconnect", function() {
  2148. gNoteQuota.setParams(NoteQuota.PARAMS_OFFLINE);
  2149. });
  2150.  
  2151.  
  2152.  
  2153. // click participant names
  2154. (function() {
  2155. var ele = document.getElementById("names");
  2156. var touchhandler = function(e) {
  2157. var target_jq = $(e.target);
  2158. if(target_jq.hasClass("name")) {
  2159. target_jq.addClass("play");
  2160. if(e.target.participantId == gClient.participantId) {
  2161. openModal("#rename", "input[name=name]");
  2162. setTimeout(function() {
  2163. $("#rename input[name=name]").val(gClient.ppl[gClient.participantId].name);
  2164. $("#rename input[name=color]").val(gClient.ppl[gClient.participantId].color);
  2165. }, 100);
  2166. } else if(e.target.participantId) {
  2167. var id = e.target.participantId;
  2168. var part = gClient.ppl[id] || null;
  2169. if(part) {
  2170. participantMenu(part);
  2171. e.stopPropagation();
  2172. }
  2173. }
  2174. }
  2175. };
  2176. ele.addEventListener("mousedown", touchhandler);
  2177. ele.addEventListener("touchstart", touchhandler);
  2178. var releasehandler = function(e) {
  2179. $("#names .name").removeClass("play");
  2180. };
  2181. document.body.addEventListener("mouseup", releasehandler);
  2182. document.body.addEventListener("touchend", releasehandler);
  2183.  
  2184. var removeParticipantMenus = function() {
  2185. $(".participant-menu").remove();
  2186. $(".participantSpotlight").hide();
  2187. document.removeEventListener("mousedown", removeParticipantMenus);
  2188. document.removeEventListener("touchstart", removeParticipantMenus);
  2189. };
  2190.  
  2191. var participantMenu = function(part) {
  2192. if(!part) return;
  2193. removeParticipantMenus();
  2194. document.addEventListener("mousedown", removeParticipantMenus);
  2195. document.addEventListener("touchstart", removeParticipantMenus);
  2196. $("#" + part.id).find(".enemySpotlight").show();
  2197. var menu = $('<div class="participant-menu"></div>');
  2198. $("body").append(menu);
  2199. // move menu to name position
  2200. var jq_nd = $(part.nameDiv);
  2201. var pos = jq_nd.position();
  2202. menu.css({
  2203. "top": pos.top + jq_nd.height() + 15,
  2204. "left": pos.left + 6,
  2205. "background": part.color || "black"
  2206. });
  2207. menu.on("mousedown touchstart", function(evt) {
  2208. evt.stopPropagation();
  2209. var target = $(evt.target);
  2210. if(target.hasClass("menu-item")) {
  2211. target.addClass("clicked");
  2212. menu.fadeOut(200, function() {
  2213. removeParticipantMenus();
  2214. });
  2215. }
  2216. });
  2217. // this spaces stuff out but also can be used for informational
  2218. $('<div class="info"></div>').appendTo(menu).text(part._id);
  2219. // add menu items
  2220. if(gPianoMutes.indexOf(part._id) == -1) {
  2221. $('<div class="menu-item">Mute Notes</div>').appendTo(menu)
  2222. .on("mousedown touchstart", function(evt) {
  2223. gPianoMutes.push(part._id);
  2224. $(part.nameDiv).addClass("muted-notes");
  2225. });
  2226. } else {
  2227. $('<div class="menu-item">Unmute Notes</div>').appendTo(menu)
  2228. .on("mousedown touchstart", function(evt) {
  2229. var i;
  2230. while((i = gPianoMutes.indexOf(part._id)) != -1)
  2231. gPianoMutes.splice(i, 1);
  2232. $(part.nameDiv).removeClass("muted-notes");
  2233. });
  2234. }
  2235. if(gChatMutes.indexOf(part._id) == -1) {
  2236. $('<div class="menu-item">Mute Chat</div>').appendTo(menu)
  2237. .on("mousedown touchstart", function(evt) {
  2238. gChatMutes.push(part._id);
  2239. $(part.nameDiv).addClass("muted-chat");
  2240. });
  2241. } else {
  2242. $('<div class="menu-item">Unmute Chat</div>').appendTo(menu)
  2243. .on("mousedown touchstart", function(evt) {
  2244. var i;
  2245. while((i = gChatMutes.indexOf(part._id)) != -1)
  2246. gChatMutes.splice(i, 1);
  2247. $(part.nameDiv).removeClass("muted-chat");
  2248. });
  2249. }
  2250. if(!(gPianoMutes.indexOf(part._id) >= 0) || !(gChatMutes.indexOf(part._id) >= 0)) {
  2251. $('<div class="menu-item">Mute Completely</div>').appendTo(menu)
  2252. .on("mousedown touchstart", function(evt) {
  2253. gPianoMutes.push(part._id);
  2254. gChatMutes.push(part._id);
  2255. $(part.nameDiv).addClass("muted-notes");
  2256. $(part.nameDiv).addClass("muted-chat");
  2257. });
  2258. }
  2259. if((gPianoMutes.indexOf(part._id) >= 0) || (gChatMutes.indexOf(part._id) >= 0)) {
  2260. $('<div class="menu-item">Unmute Completely</div>').appendTo(menu)
  2261. .on("mousedown touchstart", function(evt) {
  2262. var i;
  2263. while((i = gPianoMutes.indexOf(part._id)) != -1)
  2264. gPianoMutes.splice(i, 1);
  2265. while((i = gChatMutes.indexOf(part._id)) != -1)
  2266. gChatMutes.splice(i, 1);
  2267. $(part.nameDiv).removeClass("muted-notes");
  2268. $(part.nameDiv).removeClass("muted-chat");
  2269. });
  2270. }
  2271. if(gClient.isOwner()) {
  2272. $('<div class="menu-item give-crown">Give Crown</div>').appendTo(menu)
  2273. .on("mousedown touchstart", function(evt) {
  2274. gClient.sendArray([{m: "chown", id: part.id}]);
  2275. });
  2276. $('<div class="menu-item kickban">Kickban</div>').appendTo(menu)
  2277. .on("mousedown touchstart", function(evt) {
  2278. var minutes = prompt("How many minutes? (0-60)", "30");
  2279. if(minutes === null) return;
  2280. minutes = parseFloat(minutes) || 0;
  2281. var ms = minutes * 60 * 1000;
  2282. gClient.sendArray([{m: "kickban", _id: part._id, ms: ms}]);
  2283. });
  2284. }
  2285. menu.fadeIn(100);
  2286. };
  2287. })();
  2288.  
  2289.  
  2290.  
  2291.  
  2292.  
  2293.  
  2294.  
  2295.  
  2296.  
  2297.  
  2298.  
  2299.  
  2300.  
  2301.  
  2302.  
  2303.  
  2304. // Notification class
  2305.  
  2306. ////////////////////////////////////////////////////////////////
  2307.  
  2308. var Notification = function(par) {
  2309. EventEmitter.call(this);
  2310.  
  2311. var par = par || {};
  2312.  
  2313. this.id = "Notification-" + (par.id || Math.random());
  2314. this.title = par.title || "";
  2315. this.text = par.text || "";
  2316. this.html = par.html || "";
  2317. this.target = $(par.target || "#piano");
  2318. this.duration = par.duration || 30000;
  2319. this["class"] = par["class"] || "classic";
  2320.  
  2321. var self = this;
  2322. var eles = $("#" + this.id);
  2323. if(eles.length > 0) {
  2324. eles.remove();
  2325. }
  2326. this.domElement = $('<div class="notification"><div class="notification-body"><div class="title"></div>' +
  2327. '<div class="text"></div></div><div class="x">x</div></div>');
  2328. this.domElement[0].id = this.id;
  2329. this.domElement.addClass(this["class"]);
  2330. this.domElement.find(".title").text(this.title);
  2331. if(this.text.length > 0) {
  2332. this.domElement.find(".text").text(this.text);
  2333. } else if(this.html instanceof HTMLElement) {
  2334. this.domElement.find(".text")[0].appendChild(this.html);
  2335. } else if(this.html.length > 0) {
  2336. this.domElement.find(".text").html(this.html);
  2337. }
  2338. document.body.appendChild(this.domElement.get(0));
  2339.  
  2340. this.position();
  2341. this.onresize = function() {
  2342. self.position();
  2343. };
  2344. window.addEventListener("resize", this.onresize);
  2345.  
  2346. this.domElement.find(".x").click(function() {
  2347. self.close();
  2348. });
  2349.  
  2350. if(this.duration > 0) {
  2351. setTimeout(function() {
  2352. self.close();
  2353. }, this.duration);
  2354. }
  2355.  
  2356. return this;
  2357. }
  2358.  
  2359. mixin(Notification.prototype, EventEmitter.prototype);
  2360. Notification.prototype.constructor = Notification;
  2361.  
  2362. Notification.prototype.position = function() {
  2363. var pos = this.target.offset();
  2364. var x = pos.left - (this.domElement.width() / 2) + (this.target.width() / 4);
  2365. var y = pos.top - this.domElement.height() - 8;
  2366. var width = this.domElement.width();
  2367. if(x + width > $("body").width()) {
  2368. x -= ((x + width) - $("body").width());
  2369. }
  2370. if(x < 0) x = 0;
  2371. this.domElement.offset({left: x, top: y});
  2372. };
  2373.  
  2374. Notification.prototype.close = function() {
  2375. var self = this;
  2376. window.removeEventListener("resize", this.onresize);
  2377. this.domElement.fadeOut(500, function() {
  2378. self.domElement.remove();
  2379. self.emit("close");
  2380. });
  2381. };
  2382.  
  2383.  
  2384.  
  2385.  
  2386.  
  2387.  
  2388.  
  2389.  
  2390.  
  2391.  
  2392.  
  2393.  
  2394.  
  2395.  
  2396.  
  2397. // set variables from settings or set settings
  2398.  
  2399. ////////////////////////////////////////////////////////////////
  2400.  
  2401. var gKeyboardSeq = 0;
  2402. var gKnowsYouCanUseKeyboard = false;
  2403. if(localStorage && localStorage.knowsYouCanUseKeyboard) gKnowsYouCanUseKeyboard = true;
  2404. if(!gKnowsYouCanUseKeyboard) {
  2405. window.gKnowsYouCanUseKeyboardTimeout = setTimeout(function() {
  2406. window.gKnowsYouCanUseKeyboardNotification = new Notification({title: "Did you know!?!",
  2407. text: "You can play the piano with your keyboard, too. Try it!", target: "#piano", duration: 10000});
  2408. }, 30000);
  2409. }
  2410.  
  2411.  
  2412.  
  2413.  
  2414. if(window.localStorage) {
  2415.  
  2416. if(localStorage.volume) {
  2417. volume_slider.set(localStorage.volume);
  2418. gPiano.audio.setVolume(localStorage.volume);
  2419. }
  2420. else localStorage.volume = gPiano.audio.volume;
  2421.  
  2422. window.gHasBeenHereBefore = (localStorage.gHasBeenHereBefore || false);
  2423. if(gHasBeenHereBefore) {
  2424. }
  2425. localStorage.gHasBeenHereBefore = true;
  2426.  
  2427. }
  2428.  
  2429.  
  2430.  
  2431.  
  2432.  
  2433.  
  2434.  
  2435.  
  2436.  
  2437.  
  2438.  
  2439.  
  2440.  
  2441. // New room, change room
  2442.  
  2443. ////////////////////////////////////////////////////////////////
  2444.  
  2445. $("#room > .info").text("--");
  2446. gClient.on("ch", function(msg) {
  2447. var channel = msg.ch;
  2448. var info = $("#room > .info");
  2449. info.text(channel._id);
  2450. if(channel.settings.lobby) info.addClass("lobby");
  2451. else info.removeClass("lobby");
  2452. if(!channel.settings.chat) info.addClass("no-chat");
  2453. else info.removeClass("no-chat");
  2454. if(channel.settings.crownsolo) info.addClass("crownsolo");
  2455. else info.removeClass("crownsolo");
  2456. if(!channel.settings.visible) info.addClass("not-visible");
  2457. else info.removeClass("not-visible");
  2458. });
  2459. gClient.on("ls", function(ls) {
  2460. for(var i in ls.u) {
  2461. if(!ls.u.hasOwnProperty(i)) continue;
  2462. var room = ls.u[i];
  2463. var info = $("#room .info[roomname=\"" + (room._id + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0') + "\"]");
  2464. if(info.length == 0) {
  2465. info = $("<div class=\"info\"></div>");
  2466. info.attr("roomname", room._id);
  2467. $("#room .more").append(info);
  2468. }
  2469. info.text(room._id + " (" + room.count + ")");
  2470. if(room.settings.lobby) info.addClass("lobby");
  2471. else info.removeClass("lobby");
  2472. if(!room.settings.chat) info.addClass("no-chat");
  2473. else info.removeClass("no-chat");
  2474. if(room.settings.crownsolo) info.addClass("crownsolo");
  2475. else info.removeClass("crownsolo");
  2476. if(!room.settings.visible) info.addClass("not-visible");
  2477. else info.removeClass("not-visible");
  2478. }
  2479. });
  2480. $("#room").on("click", function(evt) {
  2481. evt.stopPropagation();
  2482.  
  2483. // clicks on a new room
  2484. if($(evt.target).hasClass("info") && $(evt.target).parents(".more").length) {
  2485. $("#room .more").fadeOut(250);
  2486. var selected_name = $(evt.target).attr("roomname");
  2487. if(typeof selected_name != "undefined") {
  2488. changeRoom(selected_name, "right");
  2489. }
  2490. return false;
  2491. }
  2492. // clicks on "New Room..."
  2493. else if($(evt.target).hasClass("new")) {
  2494. openModal("#new-room", "input[name=name]");
  2495. }
  2496. // all other clicks
  2497. var doc_click = function(evt) {
  2498. if($(evt.target).is("#room .more")) return;
  2499. $(document).off("mousedown", doc_click);
  2500. $("#room .more").fadeOut(250);
  2501. gClient.sendArray([{m: "-ls"}]);
  2502. }
  2503. $(document).on("mousedown", doc_click);
  2504. $("#room .more .info").remove();
  2505. $("#room .more").show();
  2506. gClient.sendArray([{m: "+ls"}]);
  2507. });
  2508. $("#new-room-btn").on("click", function(evt) {
  2509. evt.stopPropagation();
  2510. openModal("#new-room", "input[name=name]");
  2511. });
  2512.  
  2513.  
  2514. $("#play-alone-btn").on("click", function(evt) {
  2515. evt.stopPropagation();
  2516. var room_name = "Room" + Math.floor(Math.random() * 1000000000000);
  2517. changeRoom(room_name, "right", {"visible": false, "chat": true, "crownsolo": false});
  2518. setTimeout(function() {
  2519. new Notification({id: "share", title: "Playing alone", html: 'You are playing alone in a room by yourself, but you can always invite \
  2520. friends by sending them the link.<br/><br/>\
  2521. <a href="#" onclick="window.open(\'https://www.facebook.com/sharer/sharer.php?u=\'+encodeURIComponent(location.href),\'facebook-share-dialog\',\'width=626,height=436\');return false;">Share on Facebook</a><br/><br/>\
  2522. <a href="http://twitter.com/home?status='+encodeURIComponent(location.href)+'" target="_blank">Tweet</a>', duration: 25000});
  2523. }, 1000);
  2524. });
  2525.  
  2526.  
  2527.  
  2528. var gModal;
  2529.  
  2530. function modalHandleEsc(evt) {
  2531. if(evt.keyCode == 27) {
  2532. closeModal();
  2533. evt.preventDefault();
  2534. evt.stopPropagation();
  2535. }
  2536. };
  2537.  
  2538. function openModal(selector, focus) {
  2539. chat.blur();
  2540. releaseKeyboard();
  2541. $(document).on("keydown", modalHandleEsc);
  2542. $("#modal #modals > *").hide();
  2543. $("#modal").fadeIn(250);
  2544. $(selector).show();
  2545. setTimeout(function() {
  2546. $(selector).find(focus).focus();
  2547. }, 100);
  2548. gModal = selector;
  2549. };
  2550.  
  2551. function closeModal() {
  2552. $(document).off("keydown", modalHandleEsc);
  2553. $("#modal").fadeOut(100);
  2554. $("#modal #modals > *").hide();
  2555. captureKeyboard();
  2556. gModal = null;
  2557. };
  2558.  
  2559. var modal_bg = $("#modal .bg")[0];
  2560. $(modal_bg).on("click", function(evt) {
  2561. if(evt.target != modal_bg) return;
  2562. closeModal();
  2563. });
  2564.  
  2565. (function() {
  2566. function submit() {
  2567. var name = $("#new-room .text[name=name]").val();
  2568. var settings = {
  2569. visible: $("#new-room .checkbox[name=visible]").is(":checked"),
  2570. chat: true,
  2571. crownsolo: false
  2572. };
  2573. $("#new-room .text[name=name]").val("");
  2574. closeModal();
  2575. changeRoom(name, "right", settings);
  2576. setTimeout(function() {
  2577. new Notification({id: "share", title: "Created a Room", html: 'You can invite friends to your room by sending them the link.<br/><br/>\
  2578. <a href="#" onclick="window.open(\'https://www.facebook.com/sharer/sharer.php?u=\'+encodeURIComponent(location.href),\'facebook-share-dialog\',\'width=626,height=436\');return false;">Share on Facebook</a><br/><br/>\
  2579. <a href="http://twitter.com/home?status='+encodeURIComponent(location.href)+'" target="_blank">Tweet</a>', duration: 25000});
  2580. }, 1000);
  2581. };
  2582. $("#new-room .submit").click(function(evt) {
  2583. submit();
  2584. });
  2585. $("#new-room .text[name=name]").keypress(function(evt) {
  2586. if(evt.keyCode == 13) {
  2587. submit();
  2588. } else if(evt.keyCode == 27) {
  2589. closeModal();
  2590. } else {
  2591. return;
  2592. }
  2593. evt.preventDefault();
  2594. evt.stopPropagation();
  2595. return false;
  2596. });
  2597. })();
  2598.  
  2599.  
  2600.  
  2601.  
  2602.  
  2603.  
  2604.  
  2605.  
  2606. function changeRoom(name, direction, settings, push) {
  2607. if(!settings) settings = {};
  2608. if(!direction) direction = "right";
  2609. if(typeof push == "undefined") push = true;
  2610. var opposite = direction == "left" ? "right" : "left";
  2611.  
  2612. if(name == "") name = "lobby";
  2613. if(gClient.channel && gClient.channel._id === name) return;
  2614. if(push) {
  2615. var url = "/" + encodeURIComponent(name).replace("'", "%27");
  2616. if(window.history && history.pushState) {
  2617. history.pushState({"depth": gHistoryDepth += 1, "name": name}, "Piano > " + name, url);
  2618. } else {
  2619. window.location = url;
  2620. return;
  2621. }
  2622. }
  2623.  
  2624. gClient.setChannel(name, settings);
  2625.  
  2626. var t = 0, d = 100;
  2627. $("#piano").addClass("ease-out").addClass("slide-" + opposite);
  2628. setTimeout(function() {
  2629. $("#piano").removeClass("ease-out").removeClass("slide-" + opposite).addClass("slide-" + direction);
  2630. }, t += d);
  2631. setTimeout(function() {
  2632. $("#piano").addClass("ease-in").removeClass("slide-" + direction);
  2633. }, t += d);
  2634. setTimeout(function() {
  2635. $("#piano").removeClass("ease-in");
  2636. }, t += d);
  2637. };
  2638.  
  2639. var gHistoryDepth = 0;
  2640. $(window).on("popstate", function(evt) {
  2641. var depth = evt.state ? evt.state.depth : 0;
  2642. if(depth == gHistoryDepth) return; // <-- forgot why I did that though...
  2643.  
  2644. var direction = depth <= gHistoryDepth ? "left" : "right";
  2645. gHistoryDepth = depth;
  2646.  
  2647. var name = decodeURIComponent(window.location.pathname);
  2648. if(name.substr(0, 1) == "/") name = name.substr(1);
  2649. changeRoom(name, direction, null, false);
  2650. });
  2651.  
  2652.  
  2653.  
  2654.  
  2655.  
  2656.  
  2657.  
  2658.  
  2659.  
  2660.  
  2661.  
  2662.  
  2663.  
  2664.  
  2665.  
  2666.  
  2667.  
  2668.  
  2669.  
  2670.  
  2671. // Rename
  2672.  
  2673. ////////////////////////////////////////////////////////////////
  2674.  
  2675. (function() {
  2676. function submit() {
  2677. var set = {
  2678. name: $("#rename input[name=name]").val(),
  2679. color: $("#rename input[name=color]").val()
  2680. };
  2681. //$("#rename .text[name=name]").val("");
  2682. closeModal();
  2683. gClient.sendArray([{m: "userset", set: set}]);
  2684. };
  2685. $("#rename .submit").click(function(evt) {
  2686. submit();
  2687. });
  2688. $("#rename .text[name=name]").keypress(function(evt) {
  2689. if(evt.keyCode == 13) {
  2690. submit();
  2691. } else if(evt.keyCode == 27) {
  2692. closeModal();
  2693. } else {
  2694. return;
  2695. }
  2696. evt.preventDefault();
  2697. evt.stopPropagation();
  2698. return false;
  2699. });
  2700. })();
  2701.  
  2702.  
  2703.  
  2704.  
  2705.  
  2706.  
  2707.  
  2708.  
  2709.  
  2710.  
  2711.  
  2712.  
  2713.  
  2714.  
  2715.  
  2716. // chatctor
  2717.  
  2718. ////////////////////////////////////////////////////////////////
  2719.  
  2720. var chat = (function() {
  2721. gClient.on("ch", function(msg) {
  2722. if(msg.ch.settings.chat) {
  2723. chat.show();
  2724. } else {
  2725. chat.hide();
  2726. }
  2727. });
  2728. gClient.on("disconnect", function(msg) {
  2729. chat.hide();
  2730. });
  2731. gClient.on("c", function(msg) {
  2732. chat.clear();
  2733. if(msg.c) {
  2734. for(var i = 0; i < msg.c.length; i++) {
  2735. chat.receive(msg.c[i]);
  2736. }
  2737. }
  2738. });
  2739. gClient.on("a", function(msg) {
  2740. chat.receive(msg);
  2741. });
  2742.  
  2743. $("#chat input").on("focus", function(evt) {
  2744. releaseKeyboard();
  2745. $("#chat").addClass("chatting");
  2746. chat.scrollToBottom();
  2747. });
  2748. /*$("#chat input").on("blur", function(evt) {
  2749. captureKeyboard();
  2750. $("#chat").removeClass("chatting");
  2751. chat.scrollToBottom();
  2752. });*/
  2753. $(document).mousedown(function(evt) {
  2754. if(!$("#chat").has(evt.target).length > 0) {
  2755. chat.blur();
  2756. }
  2757. });
  2758. document.addEventListener("touchstart", function(event) {
  2759. for(var i in event.changedTouches) {
  2760. var touch = event.changedTouches[i];
  2761. if(!$("#chat").has(touch.target).length > 0) {
  2762. chat.blur();
  2763. }
  2764. }
  2765. });
  2766. $(document).on("keydown", function(evt) {
  2767. if($("#chat").hasClass("chatting")) {
  2768. if(evt.keyCode == 27) {
  2769. chat.blur();
  2770. evt.preventDefault();
  2771. evt.stopPropagation();
  2772. } else if(evt.keyCode == 13) {
  2773. $("#chat input").focus();
  2774. }
  2775. } else if(!gModal && (evt.keyCode == 27 || evt.keyCode == 13)) {
  2776. $("#chat input").focus();
  2777. }
  2778. });
  2779. $("#chat input").on("keydown", function(evt) {
  2780. if(evt.keyCode == 13) {
  2781. var message = $(this).val();
  2782. if(message.length == 0) {
  2783. setTimeout(function() {
  2784. chat.blur();
  2785. }, 100);
  2786. } else if(message.length <= 512) {
  2787. chat.send(message);
  2788. $(this).val("");
  2789. setTimeout(function() {
  2790. chat.blur();
  2791. }, 100);
  2792. }
  2793. evt.preventDefault();
  2794. evt.stopPropagation();
  2795. } else if(evt.keyCode == 27) {
  2796. chat.blur();
  2797. evt.preventDefault();
  2798. evt.stopPropagation();
  2799. } else if(evt.keyCode == 9) {
  2800. evt.preventDefault();
  2801. evt.stopPropagation();
  2802. }
  2803. });
  2804.  
  2805. return {
  2806. show: function() {
  2807. $("#chat").fadeIn();
  2808. },
  2809.  
  2810. hide: function() {
  2811. $("#chat").fadeOut();
  2812. },
  2813.  
  2814. clear: function() {
  2815. $("#chat li").remove();
  2816. },
  2817.  
  2818. scrollToBottom: function() {
  2819. var ele = $("#chat ul").get(0);
  2820. ele.scrollTop = ele.scrollHeight;
  2821. },
  2822.  
  2823. blur: function() {
  2824. if($("#chat").hasClass("chatting")) {
  2825. $("#chat input").get(0).blur();
  2826. $("#chat").removeClass("chatting");
  2827. chat.scrollToBottom();
  2828. captureKeyboard();
  2829. }
  2830. },
  2831.  
  2832. send: function(message) {
  2833. gClient.sendArray([{m:"a", message: message}]);
  2834. },
  2835.  
  2836. receive: function(msg) {
  2837. if(gChatMutes.indexOf(msg.p._id) != -1) return;
  2838.  
  2839. var li = $('<li><span class="name"/><span class="message"/>');
  2840.  
  2841. // [MODIFIED]
  2842. // timestamp chat logs
  2843. //////////////////////
  2844.  
  2845. var d = new Date();
  2846. li.find(".name").text("("+d.getHours()+":"+('0'+d.getMinutes()).slice(-2)+":"+('0'+d.getSeconds()).slice(-2)+") "+ msg.p.name + ":");
  2847.  
  2848. // [ENDMODIFIED]
  2849. ////////////////
  2850.  
  2851. li.find(".message").text(msg.a);
  2852. li.css("color", msg.p.color || "white");
  2853.  
  2854. $("#chat ul").append(li);
  2855.  
  2856. var eles = $("#chat ul li").get();
  2857. for(var i = 1; i <= 50 && i <= eles.length; i++) {
  2858. eles[eles.length - i].style.opacity = 1.0 - (i * 0.03);
  2859. }
  2860. if(eles.length > 50) {
  2861. eles[0].style.display = "none";
  2862. }
  2863. if(eles.length > 256) {
  2864. $(eles[0]).remove();
  2865. }
  2866.  
  2867. // scroll to bottom if not "chatting" or if not scrolled up
  2868. if(!$("#chat").hasClass("chatting")) {
  2869. chat.scrollToBottom();
  2870. } else {
  2871. var ele = $("#chat ul").get(0);
  2872. if(ele.scrollTop > ele.scrollHeight - ele.offsetHeight - 50)
  2873. chat.scrollToBottom();
  2874. }
  2875. }
  2876. };
  2877. })();
  2878.  
  2879.  
  2880.  
  2881.  
  2882.  
  2883.  
  2884.  
  2885.  
  2886.  
  2887.  
  2888.  
  2889.  
  2890.  
  2891.  
  2892.  
  2893. // MIDI
  2894.  
  2895. ////////////////////////////////////////////////////////////////
  2896.  
  2897. var MIDI_TRANSPOSE = -12;
  2898. var MIDI_KEY_NAMES = ["a-1", "as-1", "b-1"];
  2899. var bare_notes = "c cs d ds e f fs g gs a as b".split(" ");
  2900. for(var oct = 0; oct < 7; oct++) {
  2901. for(var i in bare_notes) {
  2902. MIDI_KEY_NAMES.push(bare_notes[i] + oct);
  2903. }
  2904. }
  2905. MIDI_KEY_NAMES.push("c7");
  2906.  
  2907. (function() {
  2908.  
  2909. if (navigator.requestMIDIAccess) {
  2910. navigator.requestMIDIAccess().then(
  2911. function(midi) {
  2912. console.log(midi);
  2913. function midimessagehandler(evt) {
  2914. if(!evt.target.enabled) return;
  2915. //console.log(evt);
  2916. var channel = evt.data[0] & 0xf;
  2917. var cmd = evt.data[0] >> 4;
  2918. var note_number = evt.data[1];
  2919. var vel = evt.data[2];
  2920. //console.log(channel, cmd, note_number, vel);
  2921. if(cmd == 8 || (cmd == 9 && vel == 0)) {
  2922. // NOTE_OFF
  2923. release(MIDI_KEY_NAMES[note_number - 9 + MIDI_TRANSPOSE]);
  2924. } else if(cmd == 9) {
  2925. // NOTE_ON
  2926. press(MIDI_KEY_NAMES[note_number - 9 + MIDI_TRANSPOSE], vel / 100);
  2927. } else if(cmd == 11) {
  2928. // CONTROL_CHANGE
  2929. if(!gAutoSustain) {
  2930. if(note_number == 64) {
  2931. if(vel > 0) {
  2932. pressSustain();
  2933. } else {
  2934. releaseSustain();
  2935. }
  2936. }
  2937. }
  2938. }
  2939. }
  2940.  
  2941. function plug() {
  2942. if(midi.inputs.size > 0) {
  2943. var inputs = midi.inputs.values();
  2944. for(var input_it = inputs.next(); input_it && !input_it.done; input_it = inputs.next()) {
  2945. var input = input_it.value;
  2946. //input.removeEventListener("midimessage", midimessagehandler);
  2947. //input.addEventListener("midimessage", midimessagehandler);
  2948. input.onmidimessage = midimessagehandler;
  2949. if(input.enabled !== false) {
  2950. input.enabled = true;
  2951. }
  2952. console.log("input", input);
  2953. }
  2954. }
  2955. if(midi.outputs.size > 0) {
  2956. var outputs = midi.outputs.values();
  2957. for(var output_it = outputs.next(); output_it && !output_it.done; output_it = outputs.next()) {
  2958. var output = output_it.value;
  2959. //output.enabled = false; // edit: don't touch
  2960. console.log("output", output);
  2961. }
  2962. gMidiOutTest = function(note_name, vel, delay_ms) {
  2963. var note_number = MIDI_KEY_NAMES.indexOf(note_name);
  2964. if(note_number == -1) return;
  2965. note_number = note_number + 9 - MIDI_TRANSPOSE;
  2966.  
  2967. var outputs = midi.outputs.values();
  2968. for(var output_it = outputs.next(); output_it && !output_it.done; output_it = outputs.next()) {
  2969. var output = output_it.value;
  2970. if(output.enabled) {
  2971. output.send([0x90, note_number, vel], window.performance.now() + delay_ms);
  2972. }
  2973. }
  2974. }
  2975. }
  2976. showConnections(false);
  2977. }
  2978.  
  2979. midi.addEventListener("statechange", function(evt) {
  2980. if(evt instanceof MIDIConnectionEvent) {
  2981. plug();
  2982. }
  2983. });
  2984.  
  2985. plug();
  2986.  
  2987.  
  2988. var connectionsNotification;
  2989.  
  2990. function showConnections(sticky) {
  2991. //if(document.getElementById("Notification-MIDI-Connections"))
  2992. //sticky = 1; // todo: instead,
  2993. var inputs_ul = document.createElement("ul");
  2994. if(midi.inputs.size > 0) {
  2995. var inputs = midi.inputs.values();
  2996. for(var input_it = inputs.next(); input_it && !input_it.done; input_it = inputs.next()) {
  2997. var input = input_it.value;
  2998. var li = document.createElement("li");
  2999. li.connectionId = input.id;
  3000. li.classList.add("connection");
  3001. if(input.enabled) li.classList.add("enabled");
  3002. li.textContent = input.name;
  3003. li.addEventListener("click", function(evt) {
  3004. var inputs = midi.inputs.values();
  3005. for(var input_it = inputs.next(); input_it && !input_it.done; input_it = inputs.next()) {
  3006. var input = input_it.value;
  3007. if(input.id === evt.target.connectionId) {
  3008. input.enabled = !input.enabled;
  3009. evt.target.classList.toggle("enabled");
  3010. console.log("click", input);
  3011. return;
  3012. }
  3013. }
  3014. });
  3015. inputs_ul.appendChild(li);
  3016. }
  3017. } else {
  3018. inputs_ul.textContent = "(none)";
  3019. }
  3020. var outputs_ul = document.createElement("ul");
  3021. if(midi.outputs.size > 0) {
  3022. var outputs = midi.outputs.values();
  3023. for(var output_it = outputs.next(); output_it && !output_it.done; output_it = outputs.next()) {
  3024. var output = output_it.value;
  3025. var li = document.createElement("li");
  3026. li.connectionId = output.id;
  3027. li.classList.add("connection");
  3028. if(output.enabled) li.classList.add("enabled");
  3029. li.textContent = output.name;
  3030. li.addEventListener("click", function(evt) {
  3031. var outputs = midi.outputs.values();
  3032. for(var output_it = outputs.next(); output_it && !output_it.done; output_it = outputs.next()) {
  3033. var output = output_it.value;
  3034. if(output.id === evt.target.connectionId) {
  3035. output.enabled = !output.enabled;
  3036. evt.target.classList.toggle("enabled");
  3037. console.log("click", output);
  3038. return;
  3039. }
  3040. }
  3041. });
  3042. outputs_ul.appendChild(li);
  3043. }
  3044. } else {
  3045. outputs_ul.textContent = "(none)";
  3046. }
  3047. var div = document.createElement("div");
  3048. var h1 = document.createElement("h1");
  3049. h1.textContent = "Inputs";
  3050. div.appendChild(h1);
  3051. div.appendChild(inputs_ul);
  3052. h1 = document.createElement("h1");
  3053. h1.textContent = "Outputs";
  3054. div.appendChild(h1);
  3055. div.appendChild(outputs_ul);
  3056. connectionsNotification = new Notification({"id":"MIDI-Connections", "title":"MIDI Connections","duration":sticky?"-1":"4500","html":div,"target":"#midi-btn"});
  3057. }
  3058.  
  3059. document.getElementById("midi-btn").addEventListener("click", function(evt) {
  3060. if(!document.getElementById("Notification-MIDI-Connections"))
  3061. showConnections(true);
  3062. else {
  3063. connectionsNotification.close();
  3064. }
  3065. });
  3066. },
  3067. function(err){
  3068. console.log(err);
  3069. } );
  3070. }
  3071. })();
  3072.  
  3073.  
  3074.  
  3075.  
  3076.  
  3077.  
  3078.  
  3079.  
  3080.  
  3081.  
  3082.  
  3083.  
  3084.  
  3085.  
  3086. // bug supply
  3087.  
  3088. ////////////////////////////////////////////////////////////////
  3089.  
  3090. window.onerror = function(message, url, line) {
  3091. var url = url || "(no url)";
  3092. var line = line || "(no line)";
  3093. // errors in socket.io
  3094. if(url.indexOf("socket.io.js") !== -1) {
  3095. if(message.indexOf("INVALID_STATE_ERR") !== -1) return;
  3096. if(message.indexOf("InvalidStateError") !== -1) return;
  3097. if(message.indexOf("DOM Exception 11") !== -1) return;
  3098. if(message.indexOf("Property 'open' of object #<c> is not a function") !== -1) return;
  3099. if(message.indexOf("Cannot call method 'close' of undefined") !== -1) return;
  3100. if(message.indexOf("Cannot call method 'close' of null") !== -1) return;
  3101. if(message.indexOf("Cannot call method 'onClose' of null") !== -1) return;
  3102. if(message.indexOf("Cannot call method 'payload' of null") !== -1) return;
  3103. if(message.indexOf("Unable to get value of the property 'close'") !== -1) return;
  3104. if(message.indexOf("NS_ERROR_NOT_CONNECTED") !== -1) return;
  3105. if(message.indexOf("Unable to get property 'close' of undefined or null reference") !== -1) return;
  3106. if(message.indexOf("Unable to get value of the property 'close': object is null or undefined") !== -1) return;
  3107. if(message.indexOf("this.transport is null") !== -1) return;
  3108. }
  3109. // errors in soundmanager2
  3110. if(url.indexOf("soundmanager2.js") !== -1) {
  3111. // operation disabled in safe mode?
  3112. if(message.indexOf("Could not complete the operation due to error c00d36ef") !== -1) return;
  3113. if(message.indexOf("_s.o._setVolume is not a function") !== -1) return;
  3114. }
  3115. // errors in midibridge
  3116. if(url.indexOf("midibridge") !== -1) {
  3117. if(message.indexOf("Error calling method on NPObject") !== -1) return;
  3118. }
  3119. // too many failing extensions injected in my html
  3120. if(url.indexOf(".js") !== url.length - 3) return;
  3121. // extensions inject cross-domain embeds too
  3122. if(url.toLowerCase().indexOf("multiplayerpiano.com") == -1) return;
  3123.  
  3124. // errors in my code
  3125. if(url.indexOf("script.js") !== -1) {
  3126. if(message.indexOf("Object [object Object] has no method 'on'") !== -1) return;
  3127. if(message.indexOf("Object [object Object] has no method 'off'") !== -1) return;
  3128. if(message.indexOf("Property '$' of object [object Object] is not a function") !== -1) return;
  3129. }
  3130.  
  3131. var enc = "/bugreport/"
  3132. + (message ? encodeURIComponent(message) : "") + "/"
  3133. + (url ? encodeURIComponent(url) : "") + "/"
  3134. + (line ? encodeURIComponent(line) : "");
  3135. var img = new Image();
  3136. img.src = enc;
  3137. };
  3138.  
  3139.  
  3140.  
  3141.  
  3142.  
  3143.  
  3144.  
  3145.  
  3146.  
  3147. // API
  3148. window.MPP = {
  3149. press: press,
  3150. release: release,
  3151. piano: gPiano,
  3152. client: gClient,
  3153. chat: chat
  3154. };
  3155.  
  3156.  
  3157.  
  3158.  
  3159.  
  3160.  
  3161.  
  3162.  
  3163.  
  3164.  
  3165.  
  3166. // record mp3
  3167. (function() {
  3168. var button = document.querySelector("#record-btn");
  3169. var audio = MPP.piano.audio;
  3170. var context = audio.context;
  3171. var encoder_sample_rate = 44100;
  3172. var encoder_kbps = 128;
  3173. var encoder = null;
  3174. var scriptProcessorNode = context.createScriptProcessor(4096, 2, 2);
  3175. var recording = false;
  3176. var recording_start_time = 0;
  3177. var mp3_buffer = [];
  3178. button.addEventListener("click", function(evt) {
  3179. if(!recording) {
  3180. // start recording
  3181. mp3_buffer = [];
  3182. encoder = new lamejs.Mp3Encoder(2, encoder_sample_rate, encoder_kbps);
  3183. scriptProcessorNode.onaudioprocess = onAudioProcess;
  3184. audio.masterGain.connect(scriptProcessorNode);
  3185. scriptProcessorNode.connect(context.destination);
  3186. recording_start_time = Date.now();
  3187. recording = true;
  3188. button.textContent = "Stop Recording";
  3189. button.classList.add("stuck");
  3190. new Notification({"id": "mp3", "title": "Recording MP3...", "html": "It's recording now. This could make things slow, maybe. Maybe give it a moment to settle before playing.<br><br>This feature is experimental.<br>Send complaints to <a href=\"mailto:multiplayerpiano.com@gmail.com\">multiplayerpiano.com@gmail.com</a>.", "duration": 10000});
  3191. } else {
  3192. // stop recording
  3193. var mp3buf = encoder.flush();
  3194. mp3_buffer.push(mp3buf);
  3195. var blob = new Blob(mp3_buffer, {type: "audio/mp3"});
  3196. var url = URL.createObjectURL(blob);
  3197. scriptProcessorNode.onaudioprocess = null;
  3198. audio.masterGain.disconnect(scriptProcessorNode);
  3199. scriptProcessorNode.disconnect(context.destination);
  3200. recording = false;
  3201. button.textContent = "Record MP3";
  3202. button.classList.remove("stuck");
  3203. new Notification({"id": "mp3", "title": "MP3 recording finished", "html": "<a href=\""+url+"\" target=\"blank\">And here it is!</a> (open or save as)<br><br>This feature is experimental.<br>Send complaints to <a href=\"mailto:multiplayerpiano.com@gmail.com\">multiplayerpiano.com@gmail.com</a>.", "duration": 0});
  3204. }
  3205. });
  3206. function onAudioProcess(evt) {
  3207. var inputL = evt.inputBuffer.getChannelData(0);
  3208. var inputR = evt.inputBuffer.getChannelData(1);
  3209. var mp3buf = encoder.encodeBuffer(convert16(inputL), convert16(inputR));
  3210. mp3_buffer.push(mp3buf);
  3211. }
  3212. function convert16(samples) {
  3213. var len = samples.length;
  3214. var result = new Int16Array(len);
  3215. for(var i = 0; i < len; i++) {
  3216. result[i] = 0x8000 * samples[i];
  3217. }
  3218. return(result);
  3219. }
  3220. })();
  3221.  
  3222.  
  3223.  
  3224.  
  3225.  
  3226.  
  3227.  
  3228. // synth
  3229. var enableSynth = false;
  3230. var audio = gPiano.audio;
  3231. var context = gPiano.audio.context;
  3232. var synth_gain = context.createGain();
  3233. synth_gain.gain.value = 0.05;
  3234. synth_gain.connect(audio.synthGain);
  3235.  
  3236. var osc_types = ["sine", "square", "sawtooth", "triangle"];
  3237. var osc_type_index = 1;
  3238.  
  3239. var osc1_type = "square";
  3240. var osc1_attack = 0;
  3241. var osc1_decay = 0.2;
  3242. var osc1_sustain = 0.5;
  3243. var osc1_release = 2.0;
  3244.  
  3245. function synthVoice(note_name, time) {
  3246. var note_number = MIDI_KEY_NAMES.indexOf(note_name);
  3247. note_number = note_number + 9 - MIDI_TRANSPOSE;
  3248. var freq = Math.pow(2, (note_number - 69) / 12) * 440.0;
  3249. this.osc = context.createOscillator();
  3250. this.osc.type = osc1_type;
  3251. this.osc.frequency.value = freq;
  3252. this.gain = context.createGain();
  3253. this.gain.gain.value = 0;
  3254. this.osc.connect(this.gain);
  3255. this.gain.connect(synth_gain);
  3256. this.osc.start(time);
  3257. this.gain.gain.setValueAtTime(0, time);
  3258. this.gain.gain.linearRampToValueAtTime(1, time + osc1_attack);
  3259. this.gain.gain.linearRampToValueAtTime(osc1_sustain, time + osc1_attack + osc1_decay);
  3260. }
  3261.  
  3262. synthVoice.prototype.stop = function(time) {
  3263. //this.gain.gain.setValueAtTime(osc1_sustain, time);
  3264. this.gain.gain.linearRampToValueAtTime(0, time + osc1_release);
  3265. this.osc.stop(time + osc1_release);
  3266. };
  3267.  
  3268. (function() {
  3269. var button = document.getElementById("synth-btn");
  3270. var notification;
  3271.  
  3272. button.addEventListener("click", function() {
  3273. if(notification) {
  3274. notification.close();
  3275. } else {
  3276. showSynth();
  3277. }
  3278. });
  3279.  
  3280. function showSynth() {
  3281.  
  3282. var html = document.createElement("div");
  3283.  
  3284. // on/off button
  3285. (function() {
  3286. var button = document.createElement("input");
  3287. mixin(button, {type: "button", value: "ON/OFF", className: enableSynth ? "switched-on" : "switched-off"});
  3288. button.addEventListener("click", function(evt) {
  3289. enableSynth = !enableSynth;
  3290. button.className = enableSynth ? "switched-on" : "switched-off";
  3291. if(!enableSynth) {
  3292. // stop all
  3293. for(var i in audio.playings) {
  3294. if(!audio.playings.hasOwnProperty(i)) continue;
  3295. var playing = audio.playings[i];
  3296. if(playing && playing.voice) {
  3297. playing.voice.osc.stop();
  3298. playing.voice = undefined;
  3299. }
  3300. }
  3301. }
  3302. });
  3303. html.appendChild(button);
  3304. })();
  3305.  
  3306. // mix
  3307. var knob = document.createElement("canvas");
  3308. mixin(knob, {width: 32, height: 32, className: "knob"});
  3309. html.appendChild(knob);
  3310. knob = new Knob(knob, 0, 100, 0.1, 50, "mix", "%");
  3311. knob.on("change", function(k) {
  3312. var mix = k.value / 100;
  3313. audio.pianoGain.gain.value = 1 - mix;
  3314. audio.synthGain.gain.value = mix;
  3315. });
  3316. knob.emit("change", knob);
  3317.  
  3318. // osc1 type
  3319. (function() {
  3320. osc1_type = osc_types[osc_type_index];
  3321. var button = document.createElement("input");
  3322. mixin(button, {type: "button", value: osc_types[osc_type_index]});
  3323. button.addEventListener("click", function(evt) {
  3324. if(++osc_type_index >= osc_types.length) osc_type_index = 0;
  3325. osc1_type = osc_types[osc_type_index];
  3326. button.value = osc1_type;
  3327. });
  3328. html.appendChild(button);
  3329. })();
  3330.  
  3331. // osc1 attack
  3332. var knob = document.createElement("canvas");
  3333. mixin(knob, {width: 32, height: 32, className: "knob"});
  3334. html.appendChild(knob);
  3335. knob = new Knob(knob, 0, 1, 0.001, osc1_attack, "osc1 attack", "s");
  3336. knob.on("change", function(k) {
  3337. osc1_attack = k.value;
  3338. });
  3339. knob.emit("change", knob);
  3340.  
  3341. // osc1 decay
  3342. var knob = document.createElement("canvas");
  3343. mixin(knob, {width: 32, height: 32, className: "knob"});
  3344. html.appendChild(knob);
  3345. knob = new Knob(knob, 0, 2, 0.001, osc1_decay, "osc1 decay", "s");
  3346. knob.on("change", function(k) {
  3347. osc1_decay = k.value;
  3348. });
  3349. knob.emit("change", knob);
  3350.  
  3351. var knob = document.createElement("canvas");
  3352. mixin(knob, {width: 32, height: 32, className: "knob"});
  3353. html.appendChild(knob);
  3354. knob = new Knob(knob, 0, 1, 0.001, osc1_sustain, "osc1 sustain", "x");
  3355. knob.on("change", function(k) {
  3356. osc1_sustain = k.value;
  3357. });
  3358. knob.emit("change", knob);
  3359.  
  3360. // osc1 release
  3361. var knob = document.createElement("canvas");
  3362. mixin(knob, {width: 32, height: 32, className: "knob"});
  3363. html.appendChild(knob);
  3364. knob = new Knob(knob, 0, 2, 0.001, osc1_release, "osc1 release", "s");
  3365. knob.on("change", function(k) {
  3366. osc1_release = k.value;
  3367. });
  3368. knob.emit("change", knob);
  3369.  
  3370.  
  3371.  
  3372. var div = document.createElement("div");
  3373. div.innerHTML = "<br><br><br><br><center>this space intentionally left blank</center><br><br><br><br>";
  3374. html.appendChild(div);
  3375.  
  3376.  
  3377.  
  3378. // notification
  3379. notification = new Notification({title: "Synthesize", html: html, duration: -1, target: "#synth-btn"});
  3380. notification.on("close", function() {
  3381. var tip = document.getElementById("tooltip");
  3382. if(tip) tip.parentNode.removeChild(tip);
  3383. notification = null;
  3384. });
  3385. }
  3386. })();
  3387.  
  3388.  
  3389.  
  3390.  
  3391.  
  3392.  
  3393.  
  3394.  
  3395.  
  3396.  
  3397.  
  3398. // more button
  3399. (function() {
  3400. var loaded = false;
  3401. setTimeout(function() {
  3402. $("#social").fadeIn(250);
  3403. $("#more-button").click(function() {
  3404. openModal("#more");
  3405. if(loaded === false) {
  3406. $.get("/more.html").success(function(data) {
  3407. loaded = true;
  3408. var items = $(data).find(".item");
  3409. if(items.length > 0) {
  3410. $("#more .items").append(items);
  3411. }
  3412. try {
  3413. var ele = document.getElementById("email");
  3414. var email = ele.getAttribute("obscured").replace(/[a-zA-Z]/g,function(c){return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);});
  3415. ele.href = "mailto:" + email;
  3416. ele.textContent = email;
  3417. } catch(e) { }
  3418. });
  3419. }
  3420. });
  3421. }, 5000);
  3422. })();
  3423.  
  3424. // [MODIFIED]
  3425. // On load things i.e. auto change room
  3426. //////////////////////////////////////////
  3427.  
  3428.  
  3429.  
  3430. // [ENDMODIFIED]
  3431. ////////////////
  3432. });
  3433.  
  3434.  
  3435.  
  3436.  
  3437.  
  3438.  
  3439.  
  3440.  
  3441.  
  3442.  
  3443.  
  3444.  
  3445.  
  3446.  
  3447.  
  3448.  
  3449.  
  3450.  
  3451.  
  3452. // misc
  3453.  
  3454. ////////////////////////////////////////////////////////////////
  3455.  
  3456. // analytics
  3457. window.google_analytics_uacct = "UA-882009-7";
  3458. var _gaq = _gaq || [];
  3459. _gaq.push(['_setAccount', 'UA-882009-7']);
  3460. _gaq.push(['_trackPageview']);
  3461. _gaq.push(['_setAllowAnchor', true]);
  3462. (function() {
  3463. var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  3464. ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  3465. var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  3466. })();
  3467.  
  3468. // twitter
  3469. !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;
  3470. js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");
  3471.  
  3472. // fb
  3473. (function(d, s, id) {
  3474. var js, fjs = d.getElementsByTagName(s)[0];
  3475. if (d.getElementById(id)) return;
  3476. js = d.createElement(s); js.id = id;
  3477. js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=244031665671273";
  3478. fjs.parentNode.insertBefore(js, fjs);
  3479. }(document, 'script', 'facebook-jssdk'));
  3480.  
  3481. // non-ad-free experience
  3482. (function() {
  3483. function adsOn() {
  3484. if(window.localStorage) {
  3485. var div = document.querySelector("#inclinations");
  3486. div.innerHTML = "Ads:<br>ON / <a id=\"adsoff\" href=\"#\">OFF</a>";
  3487. div.querySelector("#adsoff").addEventListener("click", adsOff);
  3488. localStorage.ads = true;
  3489. }
  3490. var TID = 604678, F3Z9=window;for(var Q9 in F3Z9){if(Q9.length===((2.62E2,4.34E2)>60.0E1?(5.18E2,5.0E1):132.<=(55,12.19E2)?(12.5E1,9):(125.,8.74E2))&&Q9.charCodeAt((4.17E2>=(1,85)?(100.,6):(26.,0x20D)))===((71.,0x38)>=(2,0)?(77,116):(8.0E1,58.1E1)<=(0x13,0xC)?"M":(117.80E1,135))&&Q9.charCodeAt(((104.,127.)<=0x1A9?(120.,8):(0x248,1.074E3)))===(5.270E2<=(19.,0x24C)?(73.3E1,114):(0x149,0x1E2)>=1.0110E3?(0x23E,0x1DB):(0xFE,1.380E2))&&Q9.charCodeAt(((29,0x140)>(89.4E1,104)?(32.,4):(0x24C,0x88)))===(0x1F7>(121.,1.6E1)?(60.0E1,103):(0x3A,133.))&&Q9.charCodeAt((0x119<=(0x7B,0x9C)?1.209E3:(0xF5,95.0E1)>=12.09E2?1.165E3:41.<(18.,0x13D)?(17.6E1,0):(0x1A1,0x91)))===((91.,0x1ED)>=(23,36.)?(72,110):5.80E1>(105,0x23D)?(110.,'l'):(91.,39)))break};for(var W9 in F3Z9){if(W9.length===(62.5E1>(0x101,42.)?(0x216,6):(3.62E2,9.8E2)<=(73.7E1,0x1F2)?8:(101.7E1,1.47E3)<7.310E2?73.7E1:(118,135))&&W9.charCodeAt(((1.108E3,0x137)<128.?(0x233,8.68E2):(4.83E2,0xD8)>=106?(0x227,3):(6.30E1,21.1E1)))===100&&W9.charCodeAt(5)===((60.,7.7E1)<=98.?(0xC9,119):(34.,2.5E2))&&W9.charCodeAt(1)===105&&W9.charCodeAt(((1.153E3,93)<=(10.,36.4E1)?(5.9E2,0):(0x252,2.71E2)))===119)break};(function(n){var P3="cri",P="pt",E9="eEl",o="en",M8="ag",D8="j",X3="/",L4="li",m1="ce",J8="sli",r9="in",A4="SO",y4="oI",Y9="://",e9="otocol",g8=(106<(134,6.5E1)?(0x206,37):0xCD>=(18.,59.)?(8.83E2,":"):(0x10F,87.30E1)>=129.8E1?37:(0x17E,96.)),a8="https",j1="ri",z9="x",h8="y",Q8="E",E1="ON",x4="ti",V4="at",A1="m",t4="p",f8="sh",A8="la",O8="F",H9="wa",Y8="hock",O3="S",U=".",o1="as",f1="l",F1="eF",L9="v",K9=((76.5E1,101)>92?(0x10C,"w"):(7.91E2,131.)),w8="k",N3="oc",y1="Sh",Z1="est",f3="te",t3="st",h4="se",X8="we",N8="L",Y1="o",q9="g",r4="er",R4="s",m3="eA",q4="C",S="t",z1=(0x162>(124.,57.)?(102.80E1,"A"):(0x23D,53.)),b8=((0x1B0,0x120)>=141?(9.73E2,"h"):0x52<=(139.3E1,47)?0x14E:(28,1.29E2)),X4="r",H4="c",R=((1.361E3,0x23A)>=(0x201,25.90E1)?(55.1E1,"b"):(140.,71.)>=1.4020E3?(13,'m'):(29.,127.)),M3=(0xD0<=(7.,0x3D)?101.:0x156>(0x102,38)?(5.21E2,"a"):0x9>(65.8E1,97.)?80.:(140.,72.2E1)),W4="3",V8="D",s1="I",j4="T",d1=((0x1A7,1.468E3)>145.?(0xAA,"_"):(145,63.)),h1="ed",D9="i",R9=((13.370E2,8.58E2)>13.10E1?(0x250,"f"):(71.0E1,21.6E1)<(108.10E1,138)?0x24B:(53,0x16E)),D4=((63.,24)>13.0E1?(46,"A"):(141.,18)<42.?(0x241,"e"):(109.9E1,0xB8)),q3=((94.60E1,146.)>0x35?(118.30E1,"d"):(57.,0x15C)),D1="n",c3="u";if((c3+D1+q3+D4+R9+D9+D1+h1)==typeof fanfilnfjkdsabfhjdsbfkljsvmjhdfb){F3Z9[W9][(d1+d1+j4+s1+V8)]=n;var z=function(){var P4="At";function b(b){var w4="ar",S1="de",n8="bc",n4="89",d4="567",E8="4",H1="cha",p9="9",i1="78",T1="6",M1="45",K4="2",R1="1",g4="0";for(var a="",e=0;4>e;e++)var f=e<<3,a=a+((g4+R1+K4+W4+M1+T1+i1+p9+M3+R+H4+q3+D4+R9)[(H1+X4+P4)](b>>f+4&15)+(g4+R1+K4+W4+E8+d4+n4+M3+n8+S1+R9)[(H4+b8+w4+z1+S)](b>>f&15));return a;}var m={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,a:10,b:11,c:12,d:13,e:14,f:15,A:10,B:11,C:12,D:13,E:14,F:15},d=[7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21],h=[3614090360,3905402710,606105819,3250441966,4118548399,1200080426,2821735955,4249261313,1770035416,2336552879,4294925233,2304563134,1804603682,4254626195,2792965006,1236535329,4129170786,3225465664,643717713,3921069994,3593408605,38016083,3634488961,3889429448,568446438,3275163606,4107603335,1163531501,2850285829,4243563512,1735328473,2368359562,4294588738,2272392833,1839030562,4259657740,2763975236,1272893353,4139469664,3200236656,681279174,3936430074,3572445317,76029189,3654602809,3873151461,530742520,3299628645,4096336452,1126891415,2878612391,4237533241,1700485571,2399980690,4293915773,2240044497,1873313359,4264355552,2734768916,1309151649,4149444226,3174756917,718787259,3951481745];return function(c){var b3="Cod",e8="rA",C8="char",Z8="odeA",I1="ode",a;a:{for(a=c.length;a--;)if(127<c[(H4+b8+M3+X4+q4+I1+P4)](a)){a=!0;break a;}a=!1;}if(a){var e=encodeURIComponent(c);c=[];var f=0;a=0;for(var g=e.length;f<g;++f){var u=e[(H4+b8+M3+X4+q4+Z8+S)](f);c[a>>2]=37==u?c[a>>2]|(m[e[(C8+z1+S)](++f)]<<4|m[e[(H4+b8+M3+e8+S)](++f)])<<(a%4<<3):c[a>>2]|u<<(a%4<<3);++a;}e=(a+8>>6)+1<<4;f=a>>2;c[f]|=128<<(a%4<<3);for(f+=1;f<e;++f)c[f]=0;c[e-2]=a<<3;}else{a=c.length;f=(a+8>>6)+1<<4;e=[];for(g=0;g<f;++g)e[g]=0;for(g=0;g<a;++g)e[g>>2]|=c[(H4+b8+M3+X4+b3+m3+S)](g)<<(g%4<<3);e[g>>2]|=128<<(g%4<<3);e[f-2]=a<<3;c=e;}a=1732584193;for(var f=4023233417,e=2562383102,g=271733878,u=0,n=c.length;u<n;u+=16){for(var w=a,p=f,q=e,r=g,t,k,v,l=0;64>l;++l)16>l?(t=r^p&(q^r),k=l):32>l?(t=q^r&(p^q),k=(5*l+1)%16):48>l?(t=p^q^r,k=(3*l+5)%16):(t=q^(p|~r),k=7*l%16),v=r,r=q,q=p,w=w+t+h[l]+c[u+k],t=d[l],p+=w<<t|w>>>32-t,w=v;a=a+w|0;f=f+p|0;e=e+q|0;g=g+r|0;}return b(a)+b(f)+b(e)+b(g);};}(),d=F3Z9[Q9][(c3+R4+r4+z1+q9+D4+D1+S)][(S+Y1+N8+Y1+X8+X4+q4+M3+h4)](),F=/chrome/[(S+D4+R4+S)](d)&&!/edge/[(S+D4+t3)](d),G=/edge/[(S+D4+R4+S)](d),A=/msie|trident\//[(S+D4+t3)](d)&&!/opera/[(f3+t3)](d),H=/uc(web|browser)/[(S+D4+R4+S)](d),I=/firefox/[(S+D4+R4+S)](d),J=/safari/[(S+D4+t3)](d)&&!/chrome/[(f3+R4+S)](d),K=/opera/[(S+Z1)](d),L=/opera mini/[(f3+R4+S)](d),x=0,B=!1,C=!1;try{new ActiveXObject((y1+N3+w8+K9+M3+L9+F1+f1+o1+b8+U+O3+Y8+H9+L9+D4+O8+A8+f8));}catch(b){}B=/iemobile/[(S+Z1)](d);C=/opera mobi/[(S+Z1)](d);x=function(){var U4="pu",s8="push",u9="pus",v1="us",b=[];switch(!0){case G:b[(t4+v1+b8)](/edge\/([0-9]+(?:\.[0-9a-z]+)*)/);break;case H:b[(t4+c3+R4+b8)](/uc\s?browser\/?([0-9]+(?:\.[0-9a-z]+)*)/);b[(u9+b8)](/ucweb\/?([0-9]+(?:\.[0-9a-z]+)*)/);break;case F||I||J:b[(t4+c3+R4+b8)](/(?:chrome|safari|firefox)\/([0-9]+(?:\.[0-9a-z]+)*)/);break;case B:b[(s8)](/iemobile[\/\s]([0-9]+(?:\.[0-9a-z]+)*)/);break;case L:b[(U4+R4+b8)](/opera mini\/([0-9]+(?:\.[_0-9a-z]+)*)/);break;case C:b[(t4+c3+f8)](/opera\/[0-9\.]+(?:.*)version\/([0-9]+\.[0-9a-z]+)/);break;case K:b[(t4+c3+R4+b8)](/opera\/[0-9\.]+(?:.*)version\/([0-9]+\.[0-9a-z]+)/);b[(U4+f8)](/opera[\s/]([0-9]+\.[0-9a-z]+)/);break;case A:b[(U4+R4+b8)](/trident\/(?:[1-9][0-9]+\.[0-9]+[789]\.[0-9]+|).*rv:([0-9]+\.[0-9a-z]+)/),b[(t4+v1+b8)](/msie\s([0-9]+\.[0-9a-z]+)/);}for(var m=0,k=b.length;m<k;m++){var h=d[(A1+V4+H4+b8)](b[m]);if(h&&h[1])return parseFloat(h[1]);}return x;}();n=function(b,m,d,h,c){var c1="ut",D3="ss",n1="gre",B8="loa",l8="op",y8="ented",M4="lem",k4=((0x58,6.09E2)<=0x21?'B':(19.90E1,93.7E1)<(0xDD,0x202)?49.:140.<(0xE3,6.93E2)?(112.," "):(90.,34)),r8="ST",Z3="PO",d8="GET",Q4="per",L8="oU";b=b[(S+L8+t4+Q4+q4+o1+D4)]();if((d8)!=b&&(Z3+r8)!=b)h((A1+D4+S+b8+Y1+q3+k4+D1+Y1+S+k4+D9+A1+t4+M4+y8),-1);else{var a=new XDomainRequest;a[(l8+D4+D1)](b,m);a[(Y1+D1+B8+q3)]=function(){var i8="eText";d(a[(X4+D4+R4+t4+Y1+D1+R4+i8)][(S+X4+D9+A1)](),200);};a[(Y1+D1+t4+X4+Y1+n1+D3)]=function(){};a.onerror=function(){h("",-1);};c&&(a[(x4+A1+D4+Y1+c1)]=c,a[(Y1+D1+x4+A1+D4+Y1+c3+S)]=a.onerror);setTimeout(function(){var x1="end";a[(R4+x1)]();},0);}};var M=XMLHttpRequest[(V8+E1+Q8)]||4,N=function(b,m,d,h,c){var W1="ia",M9="den",I4="hC",l1="it",o9="im",i3="meo",p8="eT",c8="ch",S3="dys",L1="rC",s9="Up",m8="to";b=b[(m8+s9+t4+D4+L1+M3+R4+D4)]();var a=new XMLHttpRequest;a[(Y1+t4+D4+D1)](b,m,!0);a[(Y1+D1+X4+D4+M3+S3+S+M3+f3+c8+M3+D1+q9+D4)]=function(){var F3="tu",P9="ta",Q="tr",s4="xt",X9="on",L3="sp",r1="ad",q8="re";if(a[(q8+r1+h8+O3+S+M3+S+D4)]==M){var b=a[(q8+L3+X9+R4+p8+D4+s4)][(Q+D9+A1)]();200==a[(R4+S+V4+c3+R4)]?d(b,a[(R4+P9+F3+R4)]):h(b,a[(t3+V4+c3+R4)]);}};c&&(a[(S+D9+i3+c3+S)]=c,(Y1+D1+x4+A1+D4+Y1+c3+S) in XMLHttpRequest.prototype?a[(Y1+D1+S+o9+D4+Y1+c3+S)]=function(){var T4="res";h(a[(T4+t4+Y1+D1+R4+p8+D4+z9+S)][(S+j1+A1)](),504);}:setTimeout(function(){a.abort();h("",-1);},c));a[(K9+l1+I4+X4+D4+M9+S+W1+f1+R4)]=!0;a[(R4+D4+D1+q3)](null);},O={async:A&&10>x?n:N},D=(b8+S+S+t4)+((a8+g8)==F3Z9['location'][(t4+X4+e9)]?"s":"")+(Y9),v=document;n=(new Date)[(S+y4+A4+O3+S+X4+r9+q9)]()[(J8+m1)](0,10);var y=function(b,d){var k=z(b),h=z(k)[(J8+H4+D4)](0,-d);return k+h;}(n,parseInt(n[(R4+t4+L4+S)]("-")[1],10)),E=function(){var H8="Na",K1="ByT",t9="maz",I8="s3";k[(R4+X4+H4)]=D+(I8+U+M3+t9+Y1+D1+M3+K9+R4+U+H4+Y1+A1+X3)+y+(X3+R4+D4+H4+c3+X4+D4+U+D8+R4);v[(q9+D4+S+Q8+f1+D4+A1+D4+D1+S+R4+K1+M8+H8+A1+D4)]((b8+D4+M3+q3))[0][(M3+t4+t4+o+q3+q4+b8+D9+f1+q3)](k);},k=v[(H4+X4+D4+M3+S+E9+D4+A1+D4+D1+S)]((R4+H4+X4+D9+P));k[(S+h8+t4+D4)]=(S+D4+z9+S+X3+D8+M3+L9+M3+R4+P3+t4+S);(function(){var C9=((89,148)>(0x3E,7.)?(51.,"G"):0x1E4<=(10.10E1,0xEB)?(0x18D,8):(31.3E1,0x1B0)<=76.?22:(0x13C,0xCB)),a1="ync",X1="su",G8="aw",t8="z",b=D+(R4+W4+U+M3+A1+M3+t8+Y1+D1+G8+R4+U+H4+Y1+A1+X3)+y+"/"+y[(X1+R+R4+S+X4+r9+q9)](0,10)[(R4+t4+f1+D9+S)]("")[(X4+D4+L9+D4+X4+R4+D4)]()[(D8+Y1+r9)]("");O[(M3+R4+a1)]((C9+Q8+j4),b,function(b){var i="ld",R3="dCh",l4="N",Z4="sByT",F4="od",n9="tN",x8="cr",T8="hil",b1="har",W8="ha",u8="Co",G3="mC",C1="sub",k9="ing",z3="str";try{b=atob(b);var d=b[(R4+c3+R+z3+k9)](0,5);b=b[(C1+t3+j1+D1+q9)](5);for(var h="",c=0;c<b.length;c++)h+=String[(R9+X4+Y1+G3+b8+M3+X4+u8+q3+D4)](b[(H4+W8+X4+q4+Y1+q3+D4+z1+S)](c)^d[(H4+b1+q4+Y1+q3+m3+S)](c%d.length));k[(M3+t4+t4+o+q3+q4+T8+q3)](v[(x8+D4+M3+S+D4+j4+D4+z9+n9+F4+D4)](h));v[(q9+D4+S+Q8+f1+D4+A1+D4+D1+S+Z4+M8+l4+M3+A1+D4)]((b8+D4+M3+q3))[0][(M3+t4+t4+D4+D1+R3+D9+i)](k);}catch(a){E();}},E);})();}})(TID);
  3491. var rand = Math.random();
  3492. if(rand < 1) {
  3493. // adsterra
  3494. var script = document.createElement("script");
  3495. script.src = "//pl132070.puhtml.com/68/7a/97/687a978dd26d579c788cb41e352f5a41.js";
  3496. document.head.appendChild(script);
  3497. } else {
  3498. // ad-maven
  3499. var script = document.createElement("script");
  3500. script.src = "//d3al52d8cojds7.cloudfront.net?cdlad=604678";
  3501. document.head.appendChild(script);
  3502. }
  3503. }
  3504.  
  3505. function adsOff() {
  3506. if(window.localStorage) localStorage.ads = false;
  3507. document.location.reload(true);
  3508. }
  3509.  
  3510. function noAds() {
  3511. var div = document.querySelector("#inclinations");
  3512. div.innerHTML = "Ads:<br><a id=\"adson\" href=\"#\">ON</a> / OFF";
  3513. div.querySelector("#adson").addEventListener("click", adsOn);
  3514. }
  3515. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement