/****************************************************************************** * Copyright (c) 2025 Ivar Antonio Salamanca Troncoso. * Todos los derechos reservados. * * AVISO DE PROTECCIÓN TÉCNICA: * Este software se distribuye en formato ejecutable, ofuscado y/o cifrado * para proteger la propiedad intelectual e industrial del autor. * * Queda estrictamente prohibida la reproducción, copia, modificación, * distribución, comunicación pública o cualquier otro uso, total o parcial, * de este software sin el consentimiento previo y por escrito del propietario. * * Queda expresamente prohibido cualquier intento de ingeniería inversa, * descompilación, desensamblado o descifrado del código fuente, así como * cualquier acción destinada a eludir las medidas de protección tecnológica * implementadas. * * El acceso a este código no otorga ninguna licencia ni derecho de uso * a menos que se especifique lo contrario en un contrato formal. ******************************************************************************//** * I.VAR Framework v1.0.0 * (c) 2012 Ivar Antonio Salamanca Troncoso, Chile * Su uso está restringido. * Su copia y distribución está prohibida * * ivar-HTML2D.core * Motor Controlador de Canvas e Interacciones * **/ const I = { /** * private start Ivar client interface */ __nit:function( ){ this.VAR = {}; this.SPACE.__init(); this.__CORE.out.log("ION® Framework | Creado por Ivar Antonio Salamanca Troncoso. | Todos los derechos reservados."); //this.DISPOSITIVOS.init(); }, __CORE:{ /** * Error manage and report exceptions */ error:function( ){ let msg = arguments.length?arguments:'error indefinido'; I.__CORE.out.err(msg); }, /** * Out object to manage the display of information via object or default console */ out:{ log:function( ){ console.log.apply(this,arguments); //console.log.apply( this, arguments ); }, err:function( ){ console.error( arguments ); } }, }, /** * TOOLKIT */ TOOL:{ /** * private property core of I.TOOL */ __CORE:{ DATA:{ nid:0, STORAGE:{} } }, /** * private initialization function for I.TOOL */ __init:function(){ }, SLEEP: function (milliseconds) { var start = new Date().getTime(); for (var i = 0; i < 1e7; i++) { if ((new Date().getTime() - start) > milliseconds){ break; } } }, UNESCAPE:function(x){ var r = /\\u([\d\w]{4})/gi; x = new String(x); x = x.replace(r, function (match, grp) { return String.fromCharCode(parseInt(grp, 16)); } ); x = unescape(x); return x; }, STORAGE:{ GET: function( name ){ if ( window.localStorage ){ return window.localStorage.getItem(name)||null; }else{ return I.TOOL.__CORE.DATA.STORAGE[name] || null; } }, SET: function( name, data ){ if ( window.localStorage ){ window.localStorage.setItem( name ,data ); }else{ I.TOOL.__CORE.DATA.STORAGE[name] = data; } } }, STRINGIFY: function( obj ){ return JSON.stringify( obj, function( key, value){ var fnBody; if (value instanceof Function || typeof value == 'function') { fnBody = value.toString(); if (fnBody.length < 8 || fnBody.substring(0, 8) !== 'function') { return '_NuFrRa_' + fnBody; } return fnBody; } if (value instanceof RegExp) { return '_PxEgEr_' + value; } return value; }); }, PARSE: function(str, date2obj){ var iso8061 = date2obj ? /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/ : false; return JSON.parse(str, function (key, value) { var prefix; if (typeof value != 'string') { return value; } if (value.length < 8) { return value; } prefix = value.substring(0, 8); if (iso8061 && value.match(iso8061)) { return new Date(value); } if (prefix === 'function') { return new Function('return ' + value)(); } if (prefix === '_PxEgEr_' || prefix === '_NuFrRa_') { return new Function('return ' + value.slice(8))(); } return value; }); }, GET_BASE64_FORM_IMAGE: function(img , format) { var canvas = document.createElement("canvas"); canvas.width = img.width; canvas.height = img.height; var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); var dataURL = canvas.toDataURL(format || "image/png"); //delete canvas; return dataURL;//.replace(/^data:image\/(png|jpg);base64,/, ""); }, COMOBJ:function(a,b){ return _.isEqual(a,b); }, VIBRATE:function(t){ if (window.navigator && window.navigator.vibrate){ navigator.vibrate(t) } }, COMOBJ2:function(a,b,ss){ var ccom = function(a,b,ia){ if (!b[ia]) return false; if (typeof a[ia] != typeof b[ia] ) return false; if (typeof a[ia] == 'object' && !a[ia].length){ if (b[ia].length) return false; if (!this.COMOBJ2(a[ia],b[ia])) return false; }else{ if (a[ia] != b[ia]) return false; } } if (a.length){ if (a.length != b.length) return false; for (var ia = 0 ; ia < a.length; ia++){ if (!ccom(a,b,ia)) return false; } }else{ var ak = Object.keys(a); var bk = Object.keys(b); if (ak.length != bk.length) return false; else{ for (var ia in ak){ if (!ccom(a,b,ia)) return false; } } } return true; }, CFG:function(){ return this.I.___CFG; }, NID:function(pre,pos){ return ((pre||'') + (I.TOOL.__CORE.DATA.nid++) + (pos||'')); }, NOW:function (){ return +new Date; }, NUM:function(n){ return this.ROUND(n||this.CFG["DEF"],this.CFG["DEC"]) }, RND:function (i,s){ var r,a; if (typeof i != undefined){ r = Math.random(); a = r * (i); } if (typeof s != undefined){ a = r * (s - i); a = i + a ; } if (!i && !s){ a = Math.random(); } return a; }, UTF_DEC :function(str_data) { var tmp_arr = [], i = 0, ac = 0, c1 = 0, c2 = 0, c3 = 0, c4 = 0; str_data += ''; while (i < str_data.length) { c1 = str_data.charCodeAt(i); if (c1 <= 191) { tmp_arr[ac++] = String.fromCharCode(c1); i++; } else if (c1 <= 223) { c2 = str_data.charCodeAt(i + 1); tmp_arr[ac++] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); i += 2; } else if (c1 <= 239) { c2 = str_data.charCodeAt(i + 1); c3 = str_data.charCodeAt(i + 2); tmp_arr[ac++] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); i += 3; } else { c2 = str_data.charCodeAt(i + 1); c3 = str_data.charCodeAt(i + 2); c4 = str_data.charCodeAt(i + 3); c1 = ((c1 & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63); c1 -= 0x10000; tmp_arr[ac++] = String.fromCharCode(0xD800 | ((c1 >> 10) & 0x3FF)); tmp_arr[ac++] = String.fromCharCode(0xDC00 | (c1 & 0x3FF)); i += 4; } } return tmp_arr.join(''); }, SUMARR:function(a,b){ var a1 = (a.length>=b.length)?a:b, a2 = (a.length>=b.length)?b:a, aR = [],rr; for (var i=0;i=b.length)?a:b, a2 = (a.length>=b.length)?b:a, aR = [],rr; for (var i=0;i=b.length)?a:b, a2 = (a.length>=b.length)?b:a, aR = [],rr; for (var i=0;i b)?a-b:(a==b)?0:b-a,2); }, DIR:function(a,b){ a = parseFloat(a||0); b = parseFloat(b||0); return (b > a)?1:(b==a)?0:-1; }, DIFARR:function(a,b){ var a1 = (a.length>=b.length)?a:b, a2 = (a.length>=b.length)?b:a, aR = []; for (var i=0;i=b.length)?a:b, a2 = (a.length>=b.length)?b:a, aR = []; for (var i=0;i1)?1:(c[3]<0.006)?0:I.TOOL.ROUND(c[3],2); } /*if (invert && col){ var t = col[0]; col[0] = col[2]; col[2] = t; col[1] = 255 - col[1]; }*/ col = col.toString(); r = types[t][0] + col + types[t][1]; return r; }, TCOLOR:function(color,t){ ncolor = []; for (var c = 0 ; c < color.length;c++){ if (color[0] < 128){ nn = color[0]*2; }else{ nn = color[0]*.2; } if (c > 3){ ncolor.push(nn); }else{ ncolor.push(color[0]); } } return I.TOOL.COLOR(ncolor,t); }, FONT:{ fonts:{}, GET:function(id, set){ set=set||false; if (!this.fonts[id]) return null; if (set) this.fonts[id].GL.font = this.fonts[id].font; return (this.fonts[id]|| null); }, GET_IMG:function(id){ if (!this.fonts[id]) return null; let font = this.fonts[id]; this.fonts[id].GL.drawImage( font.img, font.x, font.y ); return (this.fonts[id] ); }, AJUSTAR: function(GL,fs,t,f,w,tx,force){ let id = `${fs}${t}${f}${w}${tx}`; // JSON.stringify({ }); if (this.fonts[id] && !force) return this.GET(id,true); var fsize = fs; var font = (t || "") + (" " + fsize + "px ") + (f || "Arial"); GL.save(); GL.font = font; var tlen = GL.measureText(tx).width; while (tlen > w){ fsize-=1; font = (t || "") + (" " + fsize + "px ") + (f || "Arial"); GL.font = font; tlen = GL.measureText(tx).width; } GL.restore(); this.fonts[id] = this.fonts[id] || {}; this.fonts[id].GL = GL; this.fonts[id].font = font; this.fonts[id].fsize = fsize; this.fonts[id].tlen = tlen; return this.GET(id,true); }, ADJUST_DRAW(GL,fs,t,f,w,tx,x,y,color,lcolor){ let font = this.AJUSTAR(GL,fs,t,f,w,tx); let id = `${fs}${t}${f}${w}${tx}${x}${y}${color}${lcolor}`; //JSON.stringify({ fs,t,f,w,tx,x,y,color,lcolor }); if (this.fonts[id]) return this.GET(id); let cnv = document.createElement("canvas"); let ctx = cnv.getContext("2d"); ctx.font = font.font; if (color){ ctx.fillStyle = I.TOOL.COLOR(color); ctx.fillText( tx , 0,0); } if (lcolor) { ctx.strokeStyle = I.TOOL.COLOR(lcolor); ctx.strokeText( tx , 0,0); } let img = new Image(); img.src = cnv.toDataURL('image/png'); this.fonts[id] = this.fonts[id] || { }; this.fonts[id].img = img; this.fonts[id].x = x; this.fonts[id].y = y; return this.GET(id); }, SET: function(GL,fsize,type,font,max_width,text){ text = text || "" ; let id = `${fsize}${type}${font}${max_width}`; //JSON.stringify({ fsize, type,font,max_width}); if (this.fonts[id] && text === this.fonts[id].text) return this.GET(id,true); let lineBase = fsize*1.175; let _font = (type || "") + (" " + fsize + "px ") + (font || "Arial"); GL.font = _font; GL.textBaseline='Alphabetic'; GL.lineHeight = lineBase; let _measure = function(GL,text,w,fsize,ftype,font){ let tlen = GL.measureText( text ).width; let _font = "" let _fsize = fsize; while (tlen > w){ _fsize-=1; _font = (ftype || "") + (" " + _fsize + "px ") + (font || "Arial"); GL.font = _font; tlen = GL.measureText(text).width; } return { fsize:_fsize, font:_font } }; let _lines = text.split(/\n/); let Break = {}; let doit = function(){ lines = []; try { _lines.forEach( texts =>{ line = ''; words_in_line = 0; let words = texts.split(' '); for (let indx in words){ let word = words[indx]; let test = line + word; words_in_line++; let isLast = !( indx < words.length-1); let measure = GL.measureText( test ).width; if (measure > max_width){ if (words_in_line === 1){ let rms = _measure(GL,test,max_width,fsize,type,font); fsize = rms.fsize; _font = rms.font; GL.font = _font; throw Break(); } words_in_line = 0; lines.push( line ); line = word + (!isLast?' ':''); }else{ line = test + (!isLast?' ':''); } if (isLast) lines.push( line ); } }); }catch(e){ doit(); } } GL.save(); doit(); this.fonts[id] = {GL,text,lines,fsize,type,font:_font,lineBase}; GL.restore(); return this.GET(id,true); } }, GRADIENT:{ grads:{}, GET:function(id){ return (this.grads[id]|| null); }, NEW:function(GL,c){ c = c || {}; c.id = c.id || Object.keys(c).map( k=>`${c[k]}`).toString(); var GG = this.GET(c.id); if (GG) return GG; else return this.GET(this.ADD(GL,c)); }, ADD:function(GL,c){ c = c || {}; c.color = c.color || []; c.id = c.id || I.TOOL.NID(); c.inix = c.inix || 0; c.iniy = c.iniy || 0; c.endx = c.endx || 0; c.endy = c.endy || 0; c.iniw = c.iniw || 0; c.endw = c.endw || 0; c.type = c.type || "linear"; var grd = null; if (c.type == "radial") grd = GL.createRadialGradient(c.inix, c.iniy, c.iniw, c.endx, c.endy, c.endw); else grd = GL.createLinearGradient(c.inix, c.iniy,c.endx,c.endy); for (var i = 0; i < c.color.length;i++){ grd.addColorStop(c.color[i][0], I.TOOL.COLOR(c.color[i][1])); } this.grads[c.id] = grd; return c.id; } } }, /** * Variable repository synchronized with I.VAR server */ VAR:{}, /** * Object to manage client visual interface with I.VAR server */ SPACE:{ /** * private property core of I.COM */ __CORE:{ areas:{}, active_area:null, size:{}, status:false, escala: /Android|iPhone/i.test(navigator.userAgent) ? 1.0: 1.0, __status:true, ENGINE: new Worker("/ivar.space.engine?k=a19e93e2f382744e4aff6fbdf44bd1202a116e073f873a03") , resizes:[], resizing:{ test1:[0,0], test2:[0,0], }, _apply:function(){ I.SPACE.__CORE.resizing.test1 = [0,0]; I.SPACE.__CORE.resizing.test2 = [0,0]; for (let area in I.SPACE.__CORE.areas){ if (I.SPACE.__CORE.areas[area]){ let AREA = I.SPACE._UPD_SIZE(area,true); AREA = I.SPACE._UPD_CNV_POS(area); AREA = I.SPACE._UPD_SIZE(area); AREA = I.SPACE._SET_CONTROL(AREA); I.SPACE.__CORE.areas[area].canvas.focus(); if (!AREA) return; I.POINTER.__init( AREA ); I.KEYBOARD.__init( area ); I.SPACE.__CORE.ENGINE.postMessage({ type:"RESIZE", param: { id: area, cfg: AREA.cfg } }); } } }, _onresize:function( ){ if (I.SPACE.__CORE.resizing.test1[0] != 0 || I.SPACE.__CORE.resizing.test2[1] != 0) return; I.SPACE.__CORE.resizing.test1 = [ window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight ]; setTimeout(function() { I.SPACE.__CORE.resizing.test2 = [ window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth, window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight ]; if (I.SPACE.__CORE.resizing.test1[0] != I.SPACE.__CORE.resizing.test2[0] || I.SPACE.__CORE.resizing.test1[1] != I.SPACE.__CORE.resizing.test2[0] ){ setTimeout(function() { let fw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; let fh = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; if (I.SPACE.__CORE.resizing.test2[0] != fw || I.SPACE.__CORE.resizing.test2[1] != fh ){ I.SPACE.__CORE.resizing.test1 = [0,0]; I.SPACE.__CORE.resizing.test2 = [0,0]; I.SPACE.__CORE._onresize(); }else I.SPACE.__CORE._apply(); },333); }else I.SPACE.__CORE._apply(); },333); }, __pause:function(){ if ( !this.__status || !this.ENGINE) return; this.__status = false; this.ENGINE.postMessage({ type:"__pause" } ); }, __play:function(){ if ( this.__status || !this.ENGINE ) return; this.__status = true; this.ENGINE.postMessage({ type:"__play" } ); }, }, /** * private initialization function for I.COM */ __init:function( cfg ){ let ME = this; ME.__CORE.areas = {}; ME.__CORE.active_area = null; ME.__CORE.status = true; ME.__CORE.ENGINE.onmessage = function(e) { let mess = e.data ; if (mess.type == "space.new"){ ME._NEW.bind(ME)(mess.param); } if (mess.type == "dom.exec"){ I.DOM.response( I.TOOL.PARSE(mess.param) ) } if (mess.type == "audio-stream"){ if (!I.AUDIO.STREAM.__CORE.DATA.audioEl){ I.AUDIO.STREAM.init(); } I.AUDIO.STREAM.queue(mess.param); } if (mess.type == "area.reload"){ ME._RELOAD.bind(ME)(mess.param); } if (mess.type == "camara.start"){ I.DISPOSITIVOS.camara.init(); } if (mess.type == "microfono.start"){ I.DISPOSITIVOS.microfono.init(); } if (mess.type == "performance"){ I.SPACE.__CORE.escala = mess.calidad; I.SPACE.__CORE._apply(); } } window.onblur = ME.__CORE.__pause.bind(ME.__CORE); window.onfocus = ME.__CORE.__play.bind(ME.__CORE); const obs = new ResizeObserver(entries => { for (let entry of entries) { ME.__CORE.size = entry.contentRect; ME.__CORE._apply(); } }); obs.observe(document.body); if (window.addEventListener){ document.addEventListener('blur', ME.__CORE.__pause, false); document.addEventListener('focus', ME.__CORE.__play, false); window.addEventListener('beforeunload', function(){ ME.__CORE.ENGINE.postMessage({ type:"CLOSING" }); }); }else if(window.attachEvent){ document.attachEvent('blur', ME.__CORE.__pause, false); document.attachEvent('focus', ME.__CORE.__play, false); window.attachEvent('beforeunload', function(){ ME.__CORE.ENGINE.postMessage({ type:"CLOSING" }); }); } ME.__CORE.ENGINE.postMessage({ type:"init" , param:{ size: [window.innerWidth,window.innerHeight] , DPR: 1 } }); }, /** * active area */ AREA:null, _REM:function( c ){ if (!this.CORE.areas[c.id]) return; let area = this.CORE.areas[c.id]; if (!area.parent){ document.body.removeChild(area.canvas); }else{ document.getElementById(area.parent).removeChild(area.canvas); } }, _NEW:function( cfg ){ let area = { id:cfg.id, visible:cfg.visible || true, activo: cfg.activo || true, reload: cfg.reload || false, cfg : cfg.cfg || {}, canvas:null }; this.__CORE.areas[area.id] = area; area = this._UPD_SIZE( area.id ); area = this._UPD_CNV_POS( area.id ); area = this._SET_CONTROL( area ); this.__CORE.areas[area.id] = area; I.POINTER.__init( area ); I.KEYBOARD.__init( area ); }, _SET_CONTROL:function( area ){ try{ let offScreen = area.canvas.transferControlToOffscreen(); //let sprite_offScreen = area.sprite_canvas.transferControlToOffscreen(); this.__CORE.ENGINE.postMessage({ type:"control" , param:{ cfg: area.cfg, screen: offScreen } } , [offScreen] ); return area; }catch(e){ console.log("ERROR (_SET_CONTROL):",e) } }, _CREATE_CNV( area_id ){ let area = this.__CORE.areas[area_id]; if (!area) return ; if (area.canvas) area.canvas.remove(); //if (area.sprite_canvas) area.sprite_canvas.remove(); area.canvas = document.createElement('canvas'); //area.sprite_canvas = document.createElement('canvas'); if (!area.cfg.parent) document.body.appendChild(area.canvas); else document.getElementById(area.cfg.parent).appendChild(area.canvas); //area.sprite_canvas.style.backgroundColor = "transparent"; area.canvas.style.background = I.TOOL.COLOR(area.cfg.color); area.canvas.style.backgroundColor = I.TOOL.COLOR(area.cfg.color); area.canvas.tabIndex = -1; //area.sprite_canvas.style.position = "fixed"; area.canvas.style.touchAction = 'none' area.canvas.style.position = "fixed"; area.cfg.canvas_id = I.TOOL.NID('[CNV-'+area.id+']','[CNV]'); area.canvas.id = area.cfg.canvas_id; //area.sprite_canvas.id = I.TOOL.NID('[SPRT_CNV-'+area.id+']','[SPRT_CNV]'); area.canvas.style.transform = 'translateZ(0)'; area.canvas.style.opacity = '0.999'; // area.sprite_canvas.style.transform = 'translateZ(0)'; // area.sprite_canvas.style.opacity = '0.999'; //document.body.appendChild(area.sprite_canvas); let width = !area.cfg.pantalla_completa ? area.cfg.medida.ancho : area.cfg.medida_maxima; let height = !area.cfg.pantalla_completa ? area.cfg.medida.alto : area.cfg.medida_maxima; area.canvas.width = width; area.canvas.height = height; area.canvas.style.width = (width) + area.cfg.um; area.canvas.style.height = (height) + area.cfg.um; // area.sprite_canvas.width = area.cfg.medida_diagonal * 2 ; // area.sprite_canvas.height = area.cfg.medida_diagonal * 2; area.canvas.style.width = width + area.cfg.um; area.canvas.style.height = height + area.cfg.um; // area.sprite_canvas.style.width = (area.cfg.medida_diagonal * 2) + area.cfg.um; // area.sprite_canvas.style.height = (area.cfg.medida_diagonal * 2) + area.cfg.um; // area = this._UPD_SIZE( area.id ) // area = this._UPD_CNV_POS( area.id ) return area; }, _RELOAD:function( cfg){ let area = this.__CORE.areas[cfg.id]; if (!area || !cfg) return ; area.cfg = I.TOOL.EXT(area.cfg,cfg); area = this._UPD_SIZE( area.id ); area = this._UPD_CNV_POS( area.id ); return area; }, _UPD_SIZE:function( area_id ,force_new ){ let area = this.__CORE.areas[area_id]; if (!area) return ; let new_canvas = false; if ( this.__CORE.size.width != area.cfg.medida_base.ancho || this.__CORE.size.height != area.cfg.medida_base.alto || force_new ) new_canvas = true; area.cfg.medida_base.ancho = this.__CORE.size.width; area.cfg.medida_base.alto = this.__CORE.size.height; area.cfg.DPR = 1;//Math.min(window.devicePixelRatio || 1, 2.0); area.cfg.min_base_size = Math.min(area.cfg.medida_base.ancho,area.cfg.medida_base.alto); area.cfg.max_base_size = Math.max(area.cfg.medida_base.ancho,area.cfg.medida_base.alto); area.cfg.use_w = area.cfg.pantalla_completa?area.cfg.medida_base.ancho: ( (area.cfg.ajuste.horizontal=="fijo")?area.cfg.medida_inicial.ancho: ( (area.cfg.ajuste.horizontal=="relativo_minimo")?area.cfg.medida_inicial.ancho*area.cfg.min_base_size: ( (area.cfg.ajuste.horizontal=="relativo_maximo")?area.cfg.medida_inicial.ancho*area.cfg.max_base_size: ( (area.cfg.ajuste.horizontal=="relativo")?area.cfg.medida_inicial.ancho*area.cfg.medida_base.ancho : area.cfg.medida_inicial.ancho ) ) ) ); area.cfg.use_h = area.cfg.pantalla_completa?area.cfg.medida_base.alto: ( (area.cfg.ajuste.vertical=="fijo")?area.cfg.medida_inicial.alto: ( (area.cfg.ajuste.vertical=="relativo_minimo")?area.cfg.medida_inicial.alto*area.cfg.min_base_size: ( (area.cfg.ajuste.vertical=="relativo_maximo")?area.cfg.medida_inicial.alto*area.cfg.max_base_size: ( (area.cfg.ajuste.vertical=="relativo")?area.cfg.medida_inicial.alto*area.cfg.medida_base.alto : area.cfg.medida_inicial.alto ) ) ) ); area.cfg.use_x = (area.cfg.alineacion.horizontal=="fija")?area.cfg.posicion_inicial.horizontal: ( (area.cfg.alineacion.horizontal=="relativa_minima")?area.cfg.posicion_inicial.horizontal*area.cfg.min_base_size: ( (area.cfg.alineacion.horizontal=="relativa_maxima")?area.cfg.posicion_inicial.horizontal*area.cfg.max_base_size: ( (area.cfg.alineacion.horizontal=="relativa")?area.cfg.posicion_inicial.horizontal*area.cfg.medida_base.ancho : area.cfg.posicion_inicial.horizontal ) ) ); area.cfg.use_y = (area.cfg.alineacion.vertical=="fija")?area.cfg.posicion_inicial.vertical: ( (area.cfg.alineacion.vertical=="relativa_minima")?area.cfg.posicion_inicial.vertical*area.cfg.min_base_size: ( (area.cfg.alineacion.vertical=="relativa_maxima")?area.cfg.posicion_inicial.vertical*area.cfg.max_base_size: ( (area.cfg.alineacion.vertical=="relativa")?area.cfg.posicion_inicial.vertical*area.cfg.medida_base.alto : area.cfg.posicion_inicial.vertical ) ) ); area.cfg.medida_minima = Math.min(area.cfg.use_w,area.cfg.use_h); area.cfg.medida_maxima = Math.max(area.cfg.use_w,area.cfg.use_h); area.cfg.medida_diagonal = Math.sqrt(Math.pow(area.cfg.use_w,2) + Math.pow(area.cfg.use_h,2)); area.cfg.medida_media = ( area.cfg.medida_minima + area.cfg.medida_maxima )* .5; area.cfg.medida.ancho = area.cfg.use_w; area.cfg.medida.alto = area.cfg.use_h; area.cfg.posicion.horizontal = area.cfg.use_x; area.cfg.posicion.vertical = area.cfg.use_y; area.cfg.csize = [area.cfg.medida_minima,area.cfg.medida_minima]; area.cfg.centro = [area.cfg.use_w/2,area.cfg.use_h/2]; area.cfg.centro_maximo = [area.cfg.medida_maxima/2,area.cfg.medida_maxima/2]; area.cfg.centro_minimo = [area.cfg.medida_minima/2,area.cfg.medida_minima/2]; area.cfg.centro_medio = [area.cfg.medida_media/2,area.cfg.medida_media/2]; area.cfg.centro_diagonal = [area.cfg.medida_diagonal/2,area.cfg.medida_diagonal/2]; area.cfg.orientacion = (area.cfg.use_w > area.cfg.use_h)?"H":"V"; area.cfg.resolucion = area.cfg.medida_minima/320; area.cfg.escala = this.__CORE.escala; area.cfg.transparente = !!area.cfg.transparente; area.cfg.medida_sprite = { ancho: area.cfg.medida_diagonal * 2, alto: area.cfg.medida_diagonal * 2 }; area.cfg.centro_sprite = [area.cfg.medida_sprite*.5, area.cfg.medida_sprite*.5]; if (new_canvas){ area = this._CREATE_CNV( area_id ); } if (area.cfg.pantalla_completa) { var oldWidth = parseFloat(area.cfg.medida.ancho); var oldHeight = parseFloat(area.cfg.medida.alto); var nwidth = oldWidth * area.cfg.DPR * area.cfg.escala; var nheight = oldHeight * area.cfg.DPR * area.cfg.escala; //if ( oldWidth != nwidth || oldHeight != nheight) { area.canvas.width = nwidth; area.canvas.height = nheight; // area.sprite_canvas.width = nwidth; // area.sprite_canvas.height = nheight; area.canvas.style.width = oldWidth + "px";//100*area.cfg.ratio + "%"; area.canvas.style.height = oldHeight + "px";//100*area.cfg.ratio + "%"; // area.sprite_canvas.style.width = oldWidth * area.cfg.ratio + "px";//100*area.cfg.ratio + "%"; // area.sprite_canvas.style.height = oldHeight * area.cfg.ratio + "px";//100*area.cfg.ratio + "%"; //} // if ( oldHeight != nheight ) { // area.canvas.height = nheight; // //area.canvas.style.height = 100*area.cfg.ratio + "Vh"; // } } return area; }, _UPD_CNV_POS: function( area_id ){ let area = this.__CORE.areas[area_id]; if (!area) return ; let width = !area.cfg.pantalla_completa ? area.cfg.medida.ancho : area.cfg.medida_maxima; let height = !area.cfg.pantalla_completa ? area.cfg.medida.alto : area.cfg.medida_maxima; let top_w = this.__CORE.size.width; let top_h = this.__CORE.size.height; // area.sprite_canvas.style.left = (top_w*4) + area.cfg.um; // area.sprite_canvas.style.top = (top_h*4) + area.cfg.um; // area.sprite_canvas.style.zIndex = 100; // area.sprite_canvas.style.visibility = "hidden"; area.canvas.style.background = I.TOOL.COLOR(area.cfg.color); area.canvas.style.backgroundColor = I.TOOL.COLOR(area.cfg.color); area.canvas.style.visibility = (area.visible)?"visible":"hidden"; area.canvas.style.opacity = area.cfg.opacidad; area.canvas.style.zIndex = area.cfg.profundidad || 1; area.canvas.style.left = area.cfg.posicion.horizontal + area.cfg.um; area.canvas.style.top = area.cfg.posicion.vertical + area.cfg.um; return area; } }, /** * Object to manage client pointer interaction with I.VAR server */ POINTER:{ /** * private property core of I.POINTER */ __CORE:{ SHARED_DATA:{}, PUNTEROS:{}, DATA:{}, area_index:[], remove:function(areaid,pointerid){ if (I.POINTER.__CORE.DATA[areaid] && I.POINTER.__CORE.DATA[areaid][pointerid]){ I.POINTER.__CORE.DATA[areaid][pointerid] = null; delete I.POINTER.__CORE.DATA[areaid][pointerid]; } } }, /** * private initialization function for I.POINTER * for each new space */ __init:function( area ){ var supportsPassive = false; //try { var opts = Object.defineProperty({}, 'passive', { get: function() { supportsPassive = true; } }); if (window.addEventListener){ window.addEventListener("testPassive", null, opts); window.removeEventListener("testPassive", null, opts); }else if (window.attachEvent){ window.attachEvent("testPassive", null, opts); window.detachEvent("testPassive", null, opts); } var passive = supportsPassive ? { passive: true } : false; this.__CORE.PUNTEROS[area.id] = new Map(); this.__CORE.SHARED_DATA[area.id] = {} this.__CORE.SHARED_DATA[area.id].buffer = new SharedArrayBuffer(200); this.__CORE.SHARED_DATA[area.id].view = new Int32Array(this.__CORE.SHARED_DATA[area.id].buffer); const sdata = this.__CORE.SHARED_DATA[area.id]; const pointer = this.__CORE.PUNTEROS[area.id] ; const UPD_BUFFER = function( aid, pID , pos , estado, x, y){ let offset = pos * 5; sdata.view[offset] = pID ; sdata.view[offset + 1] = Math.round(x); sdata.view[offset + 2] = Math.round(y); sdata.view[offset + 3] = estado; sdata.view[offset + 4] = estado?0:1; } I.SPACE.__CORE.ENGINE.postMessage({ type:"pointer_init" , buffer: this.__CORE.SHARED_DATA[area.id].buffer, areaID:area.id }); var zoom = function(event){ if (event.scale !== 1) { event.stopPropagation(); event.preventDefault(); } }; var wheel = function(event){ if (event.ctrlKey === true || event.metaKey === true) { event.stopPropagation(); event.preventDefault(); } touch(event); }; var touch = (e) => { // if (e.pointerType === 'mouse' && e.type === 'pointermove' && e.buttons === 0) { // return; // } const pID = e.pointerId; if (e.type === 'pointerdown' || e.type ==="wheel"){ let slot = -1; for (let i = 0; i < 10; i++) { let offset = i * 5; if (sdata.view[offset] === 0 || ( sdata.view[offset + 1] == 0 && sdata.view[offset + 2] == 0 && sdata.view[offset + 3] == 0 ) ) { slot = i; break; } } if (slot !== -1){ pointer.set( pID , slot ); UPD_BUFFER(area.id, pID , slot, e.type ==="wheel"?(e.wheelDelta>0)?2:-2:1 , e.clientX, e.clientY); if (e.type ==="wheel"){ setTimeout( function(){ touch( { type:"pointerout", pointerId: e.pointerId } );} , 33); } //console.log("POINTER ["+pID+"] DOWN ", slot ) } }else if(e.type === 'pointermove'){ const slot = pointer.get( pID ); if (slot !== undefined){ UPD_BUFFER(area.id, pID , slot, 1 , e.clientX, e.clientY); //console.log("POINTER ["+pID+"] MOVE ", slot ) } }else if (e.type === 'pointerup' || e.type === 'pointercancel' || e.type === 'pointerout'){ const slot = pointer.get( pID ); if (slot !== undefined){ UPD_BUFFER(area.id, pID , slot, 0 , 0, 0); pointer.delete( pID ); //console.log("POINTER ["+pID+"] UP ", slot ) } } } if (area && area.canvas){ area.canvas.addEventListener('wheel', wheel, { passive: false }); area.canvas.addEventListener('contextmenu', function(e){ e.stopPropagation(); e.preventDefault(); }, false); area.canvas.addEventListener('touchmove', zoom,{ passive: false }); ['pointerdown', 'pointermove', 'pointerup', 'pointercancel', 'pointerout'].forEach(type => { area.canvas.addEventListener(type, touch, passive); }); // if (area.canvas.addEventListener){ // area.canvas.addEventListener('touchmove', zoom,{ passive: false }); // area.canvas.addEventListener('pointerdown', touch, passive); // area.canvas.addEventListener('MSPointerDown', touch, passive); // area.canvas.addEventListener('pointerup', touch, passive); // area.canvas.addEventListener('MSPointerUp', touch, passive); // area.canvas.addEventListener('pointermove', touch, passive); // area.canvas.addEventListener('MSPointerMove', touch, passive); // area.canvas.addEventListener('wheel', wheel, { passive: false }); // area.canvas.addEventListener('contextmenu', function(e){ // e.stopPropagation(); // e.preventDefault(); // }, false); // }else if (area.canvas.attachEvent){ // area.canvas.attachEvent('touchmove', zoom,{ passive: false }); // area.canvas.attachEvent('pointerdown', touch, passive); // area.canvas.attachEvent('MSPointerDown', touch, passive); // area.canvas.attachEvent('pointerup', touch, passive); // area.canvas.attachEvent('MSPointerUp', touch, passive); // area.canvas.attachEvent('wheel', touch, { passive: false }); // area.canvas.attachEvent('pointermove', touch, passive); // area.canvas.attachEvent('MSPointerMove', wheel, passive); // area.canvas.attachEvent('contextmenu', function(e){ // e.stopPropagation(); // e.preventDefault(); // }, false); // } } //} catch (e) {} }, GET:function( pointer_id){ return this.__COR.DATA[pointer_id] || null; } }, KEYBOARD:{ __init:function( area ){ let ME = this; var supportsPassive = false; try { var opts = Object.defineProperty({}, 'passive', { get: function() { supportsPassive = true; } }); window.addEventListener("testPassive", null, opts); window.removeEventListener("testPassive", null, opts); var passive = supportsPassive ? { passive: true } : false; var key = function(event,type){ // if (!supportsPassive){ // event.preventDefault(); // } // event.stopPropagation(); I.SPACE.__CORE.ENGINE.postMessage({ type:"keyboard_update" , param:{ key: event.keyCode || event.which, code: event.code, type : type, capslock: event.getModifierState("CapsLock"), alt: event.altKey, ctrl: event.ctrlKey, shift: event.shiftKey, repeat: event.repeat, metakey: event.metaKey, location: event.location } }); }; var keydown = function(event){ key(event,"presiona"); }; var keyup = function(event){ key(event,"suelta"); }; if (window.addEventListener){ window.addEventListener('keydown', keydown, passive); window.addEventListener('keyup', keyup, passive); }else if (window.attachEvent){ window.attachEvent('keydown', keydown, passive); window.attachEvent('keyup', keyup, passive); } } catch (e) { I.__CORE.error( e.message ); } } }, DOM:{ DATA:{}, work_exec: function( fnc,param ){ I.SPACE.__CORE.ENGINE.postMessage({ type:"dom.work_exec", param: I.TOOL.STRINGIFY({fnc,param}) } ); }, response: function( param ){ let res = param.fnc( param.param ); I.SPACE.__CORE.ENGINE.postMessage({ type:"dom.response", param : { id: param.id , response:res } } ); }, iobjeto: function( id, fnc, param , onend, endparam , endobj){ I.SPACE.__CORE.ENGINE.postMessage({ type:"dom.dom_exec", param : I.TOOL.STRINGIFY({ id , fnc, param }) } ); if (onend) onend.bind(endobj||this)(endparam); } }, DISPOSITIVOS:{ __CORE:{ status:{ camara:false, audio:false, microfono:false, }, camara:{}, audio:{ in:{}, out:{} }, microfono:{}, set_info: async function(){ const devices = await navigator.mediaDevices.enumerateDevices(); devices.map( device => { if (device.kind === 'videoinput') this.camara[device.label] = device.deviceId; if (device.kind === 'audioinput') this.audio.in[device.label] = device.deviceId; if (device.kind === 'audiooutput') this.audio.out[device.label] = device.deviceId; }); } }, microfono:{ init: async function(cfg){ this.stream( await navigator.mediaDevices.getUserMedia({audio: cfg || true})); I.DISPOSITIVOS.__CORE.set_info(); }, stream:function(data){ if (!data) return; this.microfono = new MediaRecorder(data); this.microfono.ondataavailable = (event) => { if (event.data.size > 0) { event.data.arrayBuffer().then(buffer => { I.SPACE.__CORE.ENGINE.postMessage({ type:"microfono_sync", param: buffer },[buffer.buffer]); }); } }; this.microfono.start(100); }, stop:function(){ //if } }, camara: { init: async function(){ this.stream(await navigator.mediaDevices.getUserMedia({video: true})); I.DISPOSITIVOS.__CORE.set_info(); }, stream:function(data){ if (!data) return; try { videoElement = document.createElement('video'); videoElement.srcObject = data; videoElement.autoplay = true; videoElement.onloadedmetadata = () => { setInterval( function(){ const videoFrame = new VideoFrame(videoElement, { timestamp: performance.now() }); I.SPACE.__CORE.ENGINE.postMessage({ type:"camara_sync", param: videoFrame },[videoFrame.buffer]); }, 1000 / 10) }; } catch (error) { console.error("Error al acceder a la cámara:", error); } } } }, SONIDO:{ __CORE:{ canal:{}, notas:{ 432: { // Octava 0 'C0': 16.06, 'C#0': 17.04, 'D0': 18.02, 'D#0': 19.09, 'E0': 20.19, 'F0': 21.32, 'F#0': 22.54, 'G0': 23.80, 'G#0': 25.11, 'A0': 27.00, 'A#0': 28.32, 'B0': 30.23, // Octava 1 'C1': 32.11, 'C#1': 34.07, 'D1': 36.04, 'D#1': 38.18, 'E1': 40.38, 'F1': 42.63, 'F#1': 45.08, 'G1': 47.60, 'G#1': 50.22, 'A1': 54.00, 'A#1': 56.63, 'B1': 60.46, // Octava 2 'C2': 64.22, 'C#2': 68.14, 'D2': 72.08, 'D#2': 76.37, 'E2': 80.76, 'F2': 85.26, 'F#2': 90.15, 'G2': 95.20, 'G#2': 100.44, 'A2': 108.00, 'A#2': 113.27, 'B2': 120.91, // Octava 3 'C3': 128.43, 'C#3': 136.27, 'D3': 144.17, 'D#3': 152.73, 'E3': 161.51, 'F3': 170.52, 'F#3': 180.30, 'G3': 190.41, 'G#3': 200.88, 'A3': 216.00, 'A#3': 226.54, 'B3': 241.81, // Octava 4 'C4': 256.87, 'C#4': 272.54, 'D4': 288.33, 'D#4': 305.47, 'E4': 323.02, 'F4': 341.03, 'F#4': 360.60, 'G4': 380.81, 'G#4': 401.75, 'A4': 432.00, 'A#4': 453.08, 'B4': 483.63, // Octava 5 'C5': 513.74, 'C#5': 545.08, 'D5': 576.66, 'D#5': 610.94, 'E5': 646.04, 'F5': 682.06, 'F#5': 721.20, 'G5': 761.62, 'G#5': 803.50, 'A5': 864.00, 'A#5': 906.16, 'B5': 967.26, // Octava 6 'C6': 1027.48, 'C#6': 1090.17, 'D6': 1153.33, 'D#6': 1221.87, 'E6': 1292.08, 'F6': 1364.12, 'F#6': 1442.40, 'G6': 1523.24, 'G#6': 1606.99, 'A6': 1728.00, 'A#6': 1812.33, 'B6': 1934.52, // Octava 7 'C7': 2054.96, 'C#7': 2180.33, 'D7': 2306.66, 'D#7': 2443.74, 'E7': 2584.16, 'F7': 2728.24, 'F#7': 2884.80, 'G7': 3046.48, 'G#7': 3213.98, 'A7': 3456.00, 'A#7': 3624.66, 'B7': 3869.04, // Octava 8 'C8': 4109.92, 'C#8': 4360.66, 'D8': 4613.32, 'D#8': 4887.48, 'E8': 5168.32, 'F8': 5456.48, 'F#8': 5769.60, 'G8': 6092.96, 'G#8': 6427.96, 'A8': 6912.00, 'A#8': 7249.32, 'B8': 7738.08 }, 440: { // Octava 0 'C0': 16.35, 'C#0': 17.32, 'D0': 18.35, 'D#0': 19.45, 'E0': 20.60, 'F0': 21.83, 'F#0': 23.12, 'G0': 24.50, 'G#0': 25.96, 'A0': 27.50, 'A#0': 29.14, 'B0': 30.87, // Octava 1 'C1': 32.70, 'C#1': 34.65, 'D1': 36.71, 'D#1': 38.89, 'E1': 41.20, 'F1': 43.65, 'F#1': 46.25, 'G1': 49.00, 'G#1': 51.91, 'A1': 55.00, 'A#1': 58.27, 'B1': 61.74, // Octava 2 'C2': 65.41, 'C#2': 69.30, 'D2': 73.42, 'D#2': 77.78, 'E2': 82.41, 'F2': 87.31, 'F#2': 92.50, 'G2': 98.00, 'G#2': 103.83, 'A2': 110.00, 'A#2': 116.54, 'B2': 123.47, // Octava 3 'C3': 130.81, 'C#3': 138.59, 'D3': 146.83, 'D#3': 155.56, 'E3': 164.81, 'F3': 174.61, 'F#3': 185.00, 'G3': 196.00, 'G#3': 207.65, 'A3': 220.00, 'A#3': 233.08, 'B3': 246.94, // Octava 4 'C4': 261.63, 'C#4': 277.18, 'D4': 293.66, 'D#4': 311.13, 'E4': 329.63, 'F4': 349.23, 'F#4': 369.99, 'G4': 392.00, 'G#4': 415.30, 'A4': 440.00, 'A#4': 466.16, 'B4': 493.88, // Octava 5 'C5': 523.25, 'C#5': 554.37, 'D5': 587.33, 'D#5': 622.25, 'E5': 659.25, 'F5': 698.46, 'F#5': 739.99, 'G5': 783.99, 'G#5': 830.61, 'A5': 880.00, 'A#5': 932.33, 'B5': 987.77, // Octava 6 'C6': 1046.50, 'C#6': 1108.73, 'D6': 1174.66, 'D#6': 1244.51, 'E6': 1318.51, 'F6': 1396.91, 'F#6': 1479.98, 'G6': 1567.98, 'G#6': 1661.22, 'A6': 1760.00, 'A#6': 1864.66, 'B6': 1975.53, // Octava 7 'C7': 2093.00, 'C#7': 2217.46, 'D7': 2349.32, 'D#7': 2489.02, 'E7': 2637.02, 'F7': 2793.83, 'F#7': 2959.96, 'G7': 3135.96, 'G#7': 3322.44, 'A7': 3520.00, 'A#7': 3729.31, 'B7': 3951.07, // Octava 8 'C8': 4186.01, 'C#8': 4434.92, 'D8': 4698.63, 'D#8': 4978.03, 'E8': 5274.04, 'F8': 5587.65, 'F#8': 5919.91, 'G8': 6271.93, 'G#8': 6644.88, 'A8': 7040.00, 'A#8': 7458.62, 'B8': 7902.13 } } }, nuevo:function(id){ let audio = new ( AudioContext || webkitAudioContext)(); let canal = { __core:{ _super: this.__CORE, audio: audio, osc: null, gan: null, started:false, acum:0, bpm:120, nextStepTime:0, currentTime:0, currentStep:0, volumen:.5, loop:16, caja:{ kick: { nota: "G2", nota_fin: "G0", duracion: 0.15, volumen: 1.0, tipo: "sine" , filter:{ type:"lowpass",value:2000} }, snare: { nota: "F4", nota_fin: "F4", duracion: 0.10, volumen: 0.5, tipo: "square", filter:{ type:"lowpass",value:2000}}, hat: { nota: "C6", nota_fin: "C6", duracion: 0.3, volumen: 0.3, tipo: "square",filter:{ type:"highpass",value:8000} }, laser: { nota: "C5", nota_fin: "C2", duracion: 0.15, volumen: 0.3, tipo: "sawtooth"} } }, avance_step:function(){ this.__core.nextStepTime += (60 / this.__core.bpm) / 4; this.__core.currentStep = (this.__core.currentStep + 1) % this.__core.loop; }, programa_step:function(){ while (this.__core.nextStepTime < this.__core.audio.currentTime + 0.1) { this.programa_nota(); this.avance_step(); } this.__core.timerID = setTimeout(this.programa_step, 25); }, programa_nota:function(){ Object.keys(this.__core.ritmo).forEach((track) => { const vol = (this.__core.caja[track].volumen||0) * this.__core.volumen; if (this.__core.ritmo[track][ this.__core.currentStep ]) this.tocar_nota({...this.__core.caja[track]},null,null, vol , this.__core.nextStepTime ); if (this.__core.fnc[this.__core.currentStep] ) this.__core.fnc[this.__core.currentStep](this.__core.bpm, vol, this.__core.currentStep,this.__core.nextStepTime); }); }, cambia_ritmo:function(bpm,volumen){ this.__core.bpm = bpm || this.__core.bpm; this.__core.volumen = volumen || this.__core.volumen; }, continua_ritmo:function(){ this.programa_step(); }, iniciar_ritmo:function(ritmo,bpm,volumen,loop,caja,fnc){ this.__core.caja = caja || this.__core.caja; this.programa_step = this.programa_step.bind(this); this.__core.loop = loop || 16; this.__core.volumen = volumen || .5; this.__core.ritmo = {...{ kick: new Array(this.__core.loop ).fill(false), snare: new Array(this.__core.loop ).fill(false), hat: new Array(this.__core.loop ).fill(false), laser: new Array(this.__core.loop ).fill(false) }, ...(ritmo||{})}; this.__core.bpm = bpm || 120; this.__core.currentStep = 0; this.__core.nextStepTime = this.__core.audio.currentTime; this.__core.fnc = fnc || {}; clearTimeout(this.__core.timerID ); this.programa_step(); }, detener_ritmo:function(){ clearTimeout(this.__core.timerID); }, tocar_nota:function(nota,tipo,frecuencia,volumen_multiplicador,tiempo_actual){ volumen_multiplicador = typeof(volumen_multiplicador) != "undefined"? volumen_multiplicador:1; tiempo_actual = tiempo_actual || this.__core.audio.currentTime; tipo = typeof tipo == 'undefined' ? 'square': ['square','sine', 'sawtooth', 'triangle'].indexOf(tipo) >=0 ? tipo:'square'; frecuencia = frecuencia || 432; nota.nota = nota.nota == "-" ? 0: this.__core._super.notas[frecuencia][nota.nota] || 0; nota.nota_fin = nota.nota_fin && nota.nota_fin == "-" ? 0: this.__core._super.notas[frecuencia][nota.nota_fin] || 0; nota.duracion = nota.duracion || 1 ; nota.volumen = nota.volumen || 0; const osc = this.__core.audio.createOscillator(); const gain = this.__core.audio.createGain(); if (nota.tipo) osc.type = nota.tipo && ['square','sine', 'sawtooth', 'triangle'].indexOf(nota.tipo)>= 0? nota.tipo : tipo ; else osc.type = tipo; if (nota.delay) tiempo_actual += nota.delay; if (nota.nota) osc.frequency.setValueAtTime(nota.nota , tiempo_actual ); if (nota.nota_fin) osc.frequency.exponentialRampToValueAtTime(nota.nota_fin, tiempo_actual + nota.duracion); if (nota.nota_fx) osc.frequency.exponentialRampToValueAtTime(nota.nota_fx(nota.nota,nota.nota_fin) || 0.001, tiempo_actual + nota.duracion); const volumen_nota = nota.nota? nota.volumen * volumen_multiplicador : 0.00001; const volumen_nota_fin = nota.volumen_fin? nota.volumen_fin * volumen_multiplicador : 0.00001; gain.gain.setValueAtTime(0, tiempo_actual); gain.gain.linearRampToValueAtTime( volumen_nota, tiempo_actual + 0.01); gain.gain.exponentialRampToValueAtTime( volumen_nota_fin , tiempo_actual + nota.duracion); if (nota.filter){ const filter = this.__core.audio.createBiquadFilter(); filter.type = nota.filter.type || "lowpass"; // highpass,bandpass, lowshelf, highshelf, peaking,notch,allpass filter.frequency.setValueAtTime(nota.filter.value || 5000, tiempo_actual); osc.connect(filter); filter.connect(gain); }else{ osc.connect(gain); } gain.connect(this.__core.audio.destination); osc.start(tiempo_actual); osc.stop(tiempo_actual + nota.duracion); }, tocar: function(notas,tipo,frecuencia,volumen_multiplicador){ var tiempo_actual = this.__core.audio.currentTime ; const TN = this.tocar_nota.bind(this); notas.forEach(function(nota){ // try{ TN(nota,tipo,frecuencia,volumen_multiplicador,tiempo_actual); tiempo_actual += nota.duracion; // }catch(e){ // this.__core.audio = new ( AudioContext || webkitAudioContext)(); // } } ); return true; }, detener:function(){ this.__core.audio.close(); } }; this.__CORE.canal[id] = canal; return this.__CORE.canal[id]; } }, AUDIO: { __CORE:{ DATA:{ analyzers:{}, channel:{}, }, _get:function(id){ return this.DATA; }, _analyzer:function( id, stream ){ const ctx = new AudioContext(); const mic = ctx.createMediaStreamSource(stream); const analyzer = ctx.createAnalyser(); const distortion = ctx.createWaveShaper(); const filter = ctx.createBiquadFilter(); const gainNode = ctx.createGain(); const convolver = ctx.createConvolver(); mic.connect(analyzer); analyser.connect(distortion); distortion.connect(filter); filter.connect(convolver); convolver.connect(gainNode); gainNode.connect(ctx.destination); // filter.Q.value = 100; // filter.type = "lowshelf"; // filter.frequency.value = -500; // filter.gain.value = 25; // analyzer.smoothingTimeConstant = .6; // analyzer.fftSize = 128; // analyzer.minDecibels = -10; // analyzer.maxDecibels = -10; let obj = {}; obj.bufferSize = analyzer.frequencyBinCount; obj.frequencyData = new Uint8Array(obj.bufferSize); obj.timeDomainData = new Uint8Array(obj.bufferSize); obj.ctx = ctx; obj.analyser = analyzer; obj.analyze = function( ){ this.analyser.getByteFrequencyData(this.frequencyData); this.analyser.getByteTimeDomainData(this.timeDomainData); return { frequency: obj.frequencyData, timedomain: obj.timeDomainData, samplerate:this.ctx.sampleRate, fftsize:this.analyser.fftSize, buffersize:this.bufferSize } } this.DATA.analyzers[id] = obj; } }, PROCESS:function( id ){ if (!this.__CORE.DATA.analyzers[id]) return null; return this.__CORE.DATA.analyzers[id].analyze(); }, ANALYZER:function( id ){ navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; navigator.getUserMedia({ video : false, audio : true }, (function (stream ){ this.__CORE._analyzer(id,stream); }).bind(this) , console.log); }, ___LOAD:function(c){ c = c || {}; if (!c.SRC) return; c.ID = c.ID || I.TOOL.NID("[AUDIO]","[AUDIO]"); c.o = c.o || null; c.LIB = c.LIB || null; c.AUTOPLAY = c.AUTOPLAY || false; let AudioContext = window.AudioContext||window.webkitAudioContext; let _PARAM = c.param || {}; let _PROCESS = c.PROCESS || function(){}; this.__CORE.DATA.channel[c.ID] = { ID:c.ID, AUDIO: new Audio(), CTX: new AudioContext(), SDATA:null, FDATA:null, ATDATA:[], AFDATA:[], MAXADATA:0, SOURCE:null, RDY:false, TIME:0, LOOP:_PARAM.LOOP || false, STATUS:false, CANALES:c.CANALES||2, PROC:_PROCESS, PARENT:c.o, AUTOPLAY:c.AUTOPLAY, ONLOAD:c.ONLOAD || function(){}, PARAM:c.PARAM || {}, PLAY:function(){ var canal = this; if (!canal.FDATA) return null; canal.SOURCE = canal.CTX.createBufferSource(); canal.SOURCE.buffer = canal.FDATA; canal.SOURCE.loop = true; canal.FILTER = canal.CTX.createBiquadFilter(); canal.GAIN = canal.CTX.createGain(); canal.SPLITTER = canal.CTX.createChannelSplitter(); canal.JSNODE = canal.CTX.createScriptProcessor(1024, 1, 1); canal.BUFFERSIZE = 0; canal.JSNODE.onaudioprocess = function(ape) { if (canal.STATUS){ canal.TIME += ((canal.CTX.currentTime-canal.TIME)* parseFloat(canal.SOURCE.playbackRate.value)); for (var c = 0 ; c < canal.CANALES ; c++){ I.___TIME.FUTURE({ id:"afdata"+c, fnc:function(p){ var canal = p.canal; var c = p.c; canal.ANALYSER[c].getByteFrequencyData(canal.ARR_FDATA[c]); canal.ANALYSER[c].getByteTimeDomainData(canal.ARR_TDATA[c]); }, param:{canal:canal,c:c}, o:this }); } }else{ for (var c = 0 ; c < canal.CANALES ; c++){ canal.ATDATA[c] = new Uint8Array(); canal.AFDATA[c] = new Uint8Array(); } } canal.PROC.bind(canal)(); }; canal.ANALYSER = []; for (var c = 0 ; c < canal.CANALES ; c++){ canal.ANALYSER[c] = canal.CTX.createAnalyser(); canal.ANALYSER[c].smoothingTimeConstant = .6; canal.ANALYSER[c].fftSize = 128; /*canal.ANALYSER[c].minDecibels = -90; canal.ANALYSER[c].maxDecibels = -10;*/ canal.BUFFERSIZE = canal.ANALYSER[c].frequencyBinCount; canal.ARR_FDATA[c] = new Uint8Array(canal.BUFFERSIZE); canal.ARR_TDATA[c] = new Uint8Array(canal.BUFFERSIZE); canal.SPLITTER.connect(canal.ANALYSER[c],c,0); } }, _PLAY:function(){ var canal = this; if (!canal.STATUS){ canal.JSNODE.connect(canal.CTX.destination); canal.SOURCE.connect(canal.JSNODE); canal.SOURCE.connect(canal.SPLITTER); canal.SOURCE.connect(canal.GAIN); canal.SOURCE.connect(canal.FILTER); canal.GAIN.connect(canal.CTX.destination); canal.FILTER.connect(canal.CTX.destination); canal.SOURCE.start(canal.TIME); canal.STATUS = true; } }, _STOP:function(){ var canal = this; if (canal.STATUS){ canal.JSNODE.disconnect(canal.CTX.destination); canal.SOURCE.disconnect(canal.JSNODE); canal.SOURCE.disconnect(canal.SPLITTER); canal.SOURCE.disconnect(canal.GAIN); canal.GAIN.disconnect(canal.CTX.destination); canal.SOURCE.stop(); canal.STATUS = false; } }, PAUSE:function(){ var canal = this; if (canal.STATUS){ canal._STOP(); }else{ canal._PLAY(); } } }; I.AUDIO.__CORE.DATA.channel[c.ID].PARAM = c; return this.__CORE.DATA.channel[c.ID]; } } };