Advertisement
Guest User

Untitled

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