Advertisement
Guest User

gfgggfgfg

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