10 <12html 10lang=05"de"> <12head> <12meta 10charset=05"UTF-8"> <12meta 10name=05"viewport" 10content=05"width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <12title>Misa Kitara Mobile - Digital Synth <12style> 15 :14root15 { 15 11--bg-color:15 02#08080c; 15 11--panel-bg:15 02#12121c; 15 11--accent-cyan:15 02#00f0ff; 15 11--accent-magenta:15 02#ff0055; 15 11--accent-gold:15 02#ffcc00; 15 11--grid-line:15 02#222233; 15 } 15 *15 { 15 02box-sizing:15 02border-box; 15 02user-select:15 02none; 15 02-webkit-02user-select:15 02none; 15 touch-action:15 02none; 15 } 15 12body15 { 15 02background-color:15 07var(11--bg-color); 15 02color:15 02#fff; 15 02font-family:15 -apple-system,15 BlinkMacSystemFont,15 05"Segoe UI",15 Roboto,15 02monospace; 15 02margin:15 020; 15 02padding:15 02810px; 15 02height:15 0210010vh; 15 02height:15 02100dvh; 15 02display:15 02flex; 15 02flex-direction:15 02column; 15 02gap:15 02810px; 15 02overflow:15 02hidden; 15 } 15 15/* Top Header & Display */ 15 .07header15 { 15 02background:15 07var(11--panel-bg); 15 02border:15 02110px15 02solid15 02#333; 15 02border-radius:15 02810px; 15 02padding:15 02610px15 021010px; 15 02display:15 02flex; 15 02justify-content:15 02space-between; 15 02align-items:15 02center; 15 } 15 .07title15 { 15 02font-size:15 020.910rem; 15 02font-weight:15 02900; 15 02color:15 07var(11--accent-cyan); 15 02letter-spacing:15 02110px; 15 } 15 .07status15 { 15 02font-size:15 020.710rem; 15 02color:15 07var(11--accent-gold); 15 02font-family:15 02monospace; 15 } 15 15/* Fretboard Matrix Area */ 15 .07fretboard-container15 { 15 02background:15 07var(11--panel-bg); 15 02border:15 02110px15 02solid15 02#333; 15 02border-radius:15 02810px; 15 02padding:15 02610px; 15 02display:15 02flex; 15 02flex-direction:15 02column; 15 02gap:15 02410px; 15 02flex-shrink:15 020; 15 } 15 .07string-row15 { 15 02display:15 02flex; 15 02align-items:15 02center; 15 02gap:15 02410px; 15 02height:15 022810px; 15 } 15 .07string-label15 { 15 02width:15 022410px; 15 02font-size:15 020.6510rem; 15 02font-weight:15 02bold; 15 02color:15 07var(11--accent-cyan); 15 02text-align:15 02center; 15 } 15 .07fret-buttons15 { 15 02display:15 02flex; 15 02flex:15 021; 15 02gap:15 02310px; 15 02height:15 0210010%; 15 } 15 .07fret-btn15 { 15 02flex:15 021; 15 02background:15 02#1a1a26; 15 02border:15 02110px15 02solid15 02#333; 15 02color:15 02#888; 15 02font-size:15 020.6510rem; 15 02font-weight:15 02bold; 15 02border-radius:15 02410px; 15 02display:15 02flex; 15 02align-items:15 02center; 15 02justify-content:15 02center; 15 02cursor:15 02pointer; 15 } 15 .07fret-btn.07active15 { 15 02background:15 07var(11--accent-magenta); 15 02color:15 02#fff; 15 02border-color:15 02#ff6699; 15 02box-shadow:15 02015 02015 02810px15 10rgba(02255,15 020,15 0285,15 020.6); 15 } 15 15/* Kitara XY Performance Touchpad */ 15 .07pad-container15 { 15 02flex:15 021; 15 02position:15 02relative; 15 02background:15 02#040406; 15 02border:15 02210px15 02solid15 07var(11--accent-cyan); 15 02border-radius:15 021010px; 15 02overflow:15 02hidden; 15 02box-shadow:15 02inset15 02015 02015 022010px15 10rgba(020,15 02240,15 02255,15 020.15); 15 } 15 12canvas15 { 15 02width:15 0210010%; 15 02height:15 0210010%; 15 02display:15 02block; 15 } 15 15/* FX Preset Control Bar */ 15 .07controls-bar15 { 15 02display:15 02flex; 15 02gap:15 02610px; 15 02height:15 023610px; 15 } 15 12select,15 12button15 { 15 02background:15 02#1a1a26; 15 02color:15 02#fff; 15 02border:15 02110px15 02solid15 02#444; 15 02border-radius:15 02610px; 15 02padding:15 02410px15 02810px; 15 02font-size:15 020.7510rem; 15 02font-weight:15 02bold; 15 02flex:15 021; 15 } 15 12button.07active15 { 15 02background:15 07var(11--accent-cyan); 15 02color:15 02#000; 15 } 15  <12body> <12div 10class=05"header"> <12div 10class=05"title">KITARA-MOBILE <12div 10class=05"status" 10id=05"status-display">TOUCH PAD TO PLAY <12div 10class=05"fretboard-container" 10id=05"fretboard"> <12div 10class=05"pad-container" 10id=05"pad-box"> <12canvas 10id=05"pad-canvas"> <12div 10class=05"controls-bar"> <12select 10id=05"synth-sound"> <12option 10value=05"lead">Kitara Cyber Lead <12option 10value=05"acid">303 Distorted <12option 10value=05"poly">Digital PolySaw <12option 10value=05"sub">Sub Bass Heavy <12button 10id=05"delay-btn">DELAY: ON <12script> 15 15// Base Frequencies for 6 Standard Guitar Strings (E2, A2, D3, G3, B3, E4) 15 02const15 baseNotes15 =15 [0240,15 0245,15 0250,15 0255,15 0259,15 0264];15  15 02const15 availableFrets15 =15 [020,15 021,15 023,15 025,15 027,15 028,15 0210,15 0212]; 15 02const15 stringStates15 =15 [020,15 020,15 020,15 020,15 020,15 020];15 15// Selected fret per string 15 02let15 audioCtx15 =15 02null; 15 02let15 masterGain,15 filterNode,15 driveNode,15 delayNode,15 delayFeedback; 15 02let15 delayActive15 =15 02true; 15 02let15 activeVoices15 =15 {};15 15// Tracks active touch sound voices 15 02function15 midiToFreq(midi)15 { 15 02return15 0244015 *15 10Math.pow(022,15 (midi15 -15 0269)15 /15 0212); 15 } 15 15// Audio Engine Setup 15 02function15 initAudio()15 { 15 02if15 (audioCtx)15 02return; 15 audioCtx15 =15 06new15 (10window.AudioContext15 ||15 10window.webkitAudioContext)({15 latencyHint:15 05'interactive'15 }); 15 masterGain15 =15 audioCtx.createGain(); 15 masterGain.gain.value15 =15 020.4; 15 filterNode15 =15 audioCtx.createBiquadFilter(); 15 filterNode.type15 =15 05'lowpass'; 15 filterNode.frequency.value15 =15 022500; 15 filterNode.Q.value15 =15 024; 15 driveNode15 =15 audioCtx.createWaveShaper(); 15 driveNode.curve15 =15 makeDistortionCurve(0260); 15 15// Delay FX 15 delayNode15 =15 audioCtx.createDelay(); 15 delayNode.delayTime.value15 =15 020.25;15 15// 1/8 note vibe 15 delayFeedback15 =15 audioCtx.createGain(); 15 delayFeedback.gain.value15 =15 020.4; 15 delayNode.connect(delayFeedback); 15 delayFeedback.connect(delayNode); 15 15// Routing 15 filterNode.connect(driveNode); 15 driveNode.connect(masterGain); 15 driveNode.connect(delayNode); 15 delayNode.connect(masterGain); 15 masterGain.connect(audioCtx.destination); 15 } 15 02function15 makeDistortionCurve(amount)15 { 15 02let15 k15 =15 amount,15 n15 =15 0244100,15 curve15 =15 06new15 10Float32Array(n),15 deg15 =15 10Math.PI15 /15 02180; 15 02for15 (02let15 i15 =15 020;15 i15 <15 n;15 ++i)15 { 15 02let15 x15 =15 i15 *15 02215 /15 n15 -15 021; 15 curve[i]15 =15 (02315 +15 k)15 *15 x15 *15 022015 *15 deg15 /15 (10Math.PI15 +15 k15 *15 10Math.abs(x)); 15 } 15 02return15 curve; 15 } 15 15// Play Kitara Voice on String Trigger 15 02function15 startVoice(touchId,15 stringIndex,15 xRatio,15 yRatio)15 { 15 initAudio(); 15 02if15 (audioCtx.state15 ===15 05'suspended')15 audioCtx.resume(); 15 02const15 midiNote15 =15 baseNotes[stringIndex]15 +15 stringStates[stringIndex]; 15 02const15 freq15 =15 midiToFreq(midiNote); 15 02const15 preset15 =15 10document.getElementById(05'synth-sound').value; 15 02const15 osc115 =15 audioCtx.createOscillator(); 15 02const15 osc215 =15 audioCtx.createOscillator(); 15 02const15 voiceGain15 =15 audioCtx.createGain(); 15 02if15 (preset15 ===15 05'acid')15 { 15 osc1.type15 =15 05'sawtooth';15 osc2.type15 =15 05'sawtooth'; 15 osc2.detune.value15 =15 0212; 15 }15 02else15 02if15 (preset15 ===15 05'poly')15 { 15 osc1.type15 =15 05'sawtooth';15 osc2.type15 =15 05'square'; 15 osc2.detune.value15 =15 -027; 15 }15 02else15 02if15 (preset15 ===15 05'sub')15 { 15 osc1.type15 =15 05'triangle';15 osc2.type15 =15 05'sine'; 15 }15 02else15 {15 15// Kitara Lead 15 osc1.type15 =15 05'sawtooth';15 osc2.type15 =15 05'square'; 15 osc2.detune.value15 =15 025; 15 } 15 osc1.frequency.setValueAtTime(freq,15 audioCtx.currentTime); 15 osc2.frequency.setValueAtTime(freq,15 audioCtx.currentTime); 15 osc1.connect(voiceGain); 15 osc2.connect(voiceGain); 15 voiceGain.connect(filterNode); 15 15// Fast Attack Envelope 15 voiceGain.gain.setValueAtTime(020.01,15 audioCtx.currentTime); 15 voiceGain.gain.linearRampToValueAtTime(020.8,15 audioCtx.currentTime15 +15 020.01); 15 osc1.start();15 osc2.start(); 15 activeVoices[touchId]15 =15 {15 osc1,15 osc2,15 voiceGain,15 stringIndex15 }; 15 updateSynthParameters(xRatio,15 yRatio); 15 } 15 02function15 updateVoice(touchId,15 xRatio,15 yRatio,15 stringIndex)15 { 15 02if15 (!activeVoices[touchId])15 02return; 15 15// Pitch shift if finger slides to another string zone 15 02if15 (activeVoices[touchId].stringIndex15 !==15 stringIndex)15 { 15 02const15 midiNote15 =15 baseNotes[stringIndex]15 +15 stringStates[stringIndex]; 15 02const15 freq15 =15 midiToFreq(midiNote); 15 02const15 now15 =15 audioCtx.currentTime; 15 activeVoices[touchId].osc1.frequency.setTargetAtTime(freq,15 now,15 020.01); 15 activeVoices[touchId].osc2.frequency.setTargetAtTime(freq,15 now,15 020.01); 15 activeVoices[touchId].stringIndex15 =15 stringIndex; 15 } 15 updateSynthParameters(xRatio,15 yRatio); 15 } 15 02function15 stopVoice(touchId)15 { 15 02if15 (!activeVoices[touchId])15 02return; 15 02const15 {15 osc1,15 osc2,15 voiceGain15 }15 =15 activeVoices[touchId]; 15 02const15 now15 =15 audioCtx.currentTime; 15 voiceGain.gain.cancelScheduledValues(now); 15 voiceGain.gain.setTargetAtTime(020.001,15 now,15 020.05); 15 setTimeout(()15 =>15 { 15 02try15 {15 osc1.stop();15 osc2.stop();15 osc1.disconnect();15 osc2.disconnect();15 }15 02catch(e){} 15 },15 02100); 15 06delete15 activeVoices[touchId]; 15 } 15 02function15 updateSynthParameters(xRatio,15 yRatio)15 { 15 02if15 (!audioCtx)15 02return; 15 02const15 now15 =15 audioCtx.currentTime; 15 15// X-Axis controls Filter Cutoff (100 Hz - 8000 Hz) 15 02const15 cutoff15 =15 0210015 *15 10Math.pow(0280,15 xRatio); 15 filterNode.frequency.setTargetAtTime(cutoff,15 now,15 020.01); 15 15// Y-Axis controls Resonance & Distortion Gain 15 filterNode.Q.setTargetAtTime(02215 +15 (yRatio15 *15 0216),15 now,15 020.01); 15  15 10document.getElementById(05'status-display').innerText15 =15  15 05`05CUTOFF: 05${10Math.round(cutoff)05}05Hz | RES: 05${10Math.round(02215 +15 yRatio15 *15 0216)05}05`; 15 } 15 15// Render Fretboard UI 15 02const15 fretboardEl15 =15 10document.getElementById(05'fretboard'); 15 02const15 stringNames15 =15 [05'E2',15 05'A2',15 05'D3',15 05'G3',15 05'B3',15 05'E4']; 15 stringNames.forEach((name,15 sIdx)15 =>15 { 15 02const15 row15 =15 10document.createElement(05'div'); 15 row.className15 =15 05'string-row'; 15 02const15 label15 =15 10document.createElement(05'div'); 15 label.className15 =15 05'string-label'; 15 label.innerText15 =15 name[020]15 +15 name[021]; 15 row.appendChild(label); 15 02const15 fretContainer15 =15 10document.createElement(05'div'); 15 fretContainer.className15 =15 05'fret-buttons'; 15 availableFrets.forEach((fret)15 =>15 { 15 02const15 btn15 =15 10document.createElement(05'div'); 15 btn.className15 =15 05`05fret-btn 05${fret15 ===15 02015 ?15 05'active'15 :15 05''05}05`; 15 btn.innerText15 =15 fret15 ===15 02015 ?15 05'O'15 :15 fret; 15 btn.dataset.string15 =15 sIdx; 15 btn.dataset.fret15 =15 fret; 15 btn.addEventListener(05'pointerdown',15 (e)15 =>15 { 15 e.preventDefault(); 15 stringStates[sIdx]15 =15 fret; 15 row.querySelectorAll(05'.fret-btn').forEach(b15 =>15 b.classList.remove(05'active')); 15 btn.classList.add(05'active'); 15 }); 15 fretContainer.appendChild(btn); 15 }); 15 row.appendChild(fretContainer); 15 fretboardEl.appendChild(row); 15 }); 15 15// Touchpad & Canvas Performance Rendering 15 02const15 padBox15 =15 10document.getElementById(05'pad-box'); 15 02const15 canvas15 =15 10document.getElementById(05'pad-canvas'); 15 02const15 ctx15 =15 canvas.getContext(05'2d'); 15 02let15 touches15 =15 []; 15 02function15 resizeCanvas()15 { 15 canvas.width15 =15 padBox.clientWidth; 15 canvas.height15 =15 padBox.clientHeight; 15 } 15 10window.addEventListener(05'resize',15 resizeCanvas); 15 resizeCanvas(); 15 02function15 getPadCoordinates(e)15 { 15 02const15 rect15 =15 padBox.getBoundingClientRect(); 15 02const15 touchList15 =15 e.touches15 ?15 10Array.02from(e.touches)15 :15 [e]; 15 02return15 touchList.map(t15 =>15 { 15 02const15 x15 =15 10Math.max(020,15 10Math.min(rect.width,15 t.clientX15 -15 rect.left)); 15 02const15 y15 =15 10Math.max(020,15 10Math.min(rect.height,15 t.clientY15 -15 rect.top)); 15 02const15 xRatio15 =15 x15 /15 rect.width; 15 02const15 yRatio15 =15 02115 -15 (y15 /15 rect.height); 15 15// 6 Virtual String Zones on Y-Axis 15 02const15 stringIndex15 =15 10Math.min(025,15 10Math.floor((y15 /15 rect.height)15 *15 026)); 15 02return15 {15 id:15 t.identifier15 ??15 05'mouse',15 x,15 y,15 xRatio,15 yRatio,15 stringIndex15 }; 15 }); 15 } 15 02function15 handleTouchStart(e)15 { 15 e.preventDefault(); 15 02const15 currentTouches15 =15 getPadCoordinates(e); 15 currentTouches.forEach(t15 =>15 { 15 startVoice(t.id,15 t.stringIndex,15 t.xRatio,15 t.yRatio); 15 }); 15 touches15 =15 currentTouches; 15 } 15 02function15 handleTouchMove(e)15 { 15 e.preventDefault(); 15 02const15 currentTouches15 =15 getPadCoordinates(e); 15 currentTouches.forEach(t15 =>15 { 15 updateVoice(t.id,15 t.xRatio,15 t.yRatio,15 t.stringIndex); 15 }); 15 touches15 =15 currentTouches; 15 } 15 02function15 handleTouchEnd(e)15 { 15 e.preventDefault(); 15 02const15 remainingTouches15 =15 getPadCoordinates(e); 15 02const15 remainingIds15 =15 06new15 10Set(remainingTouches.map(t15 =>15 t.id)); 15 10Object.keys(activeVoices).forEach(id15 =>15 { 15 02if15 (!remainingIds.has(id15 ===15 05'mouse'15 ?15 05'mouse'15 :15 10Number(id)))15 { 15 stopVoice(id); 15 } 15 }); 15 touches15 =15 remainingTouches; 15 } 15 padBox.addEventListener(05'touchstart',15 handleTouchStart,15 {15 passive:15 02false15 }); 15 padBox.addEventListener(05'touchmove',15 handleTouchMove,15 {15 passive:15 02false15 }); 15 padBox.addEventListener(05'touchend',15 handleTouchEnd,15 {15 passive:15 02false15 }); 15 02let15 isMouseDown15 =15 02false; 15 padBox.addEventListener(05'mousedown',15 (e)15 =>15 {15 isMouseDown15 =15 02true;15 handleTouchStart(e);15 }); 15 10window.addEventListener(05'mousemove',15 (e)15 =>15 {15 02if15 (isMouseDown)15 handleTouchMove(e);15 }); 15 10window.addEventListener(05'mouseup',15 (e)15 =>15 {15 02if15 (isMouseDown)15 {15 isMouseDown15 =15 02false;15 handleTouchEnd(e);15 }15 }); 15 15// Visualizer Loop 15 02function15 drawPad()15 { 15 requestAnimationFrame(drawPad); 15 ctx.fillStyle15 =15 05'#040406'; 15 ctx.fillRect(020,15 020,15 canvas.width,15 canvas.height); 15 15// Draw 6 Virtual String Bands (Kitara Style) 15 02const15 bandHeight15 =15 canvas.height15 /15 026; 15 ctx.lineWidth15 =15 021; 15 02for15 (02let15 i15 =15 020;15 i15 <15 026;15 i++)15 { 15 ctx.strokeStyle15 =15 05'#181828'; 15 ctx.beginPath(); 15 ctx.moveTo(020,15 i15 *15 bandHeight); 15 ctx.lineTo(canvas.width,15 i15 *15 bandHeight); 15 ctx.stroke(); 15 15// Highlight Active Fretted String Lines 15 ctx.strokeStyle15 =15 05'rgba(0, 240, 255, 0.15)'; 15 ctx.beginPath(); 15 ctx.moveTo(020,15 i15 *15 bandHeight15 +15 bandHeight15 /15 022); 15 ctx.lineTo(canvas.width,15 i15 *15 bandHeight15 +15 bandHeight15 /15 022); 15 ctx.stroke(); 15 } 15 15// Draw Touch Pointers 15 touches.forEach(t15 =>15 { 15 15// Horizontal / Vertical Crosshair 15 ctx.strokeStyle15 =15 05'rgba(255, 0, 85, 0.4)'; 15 ctx.beginPath();15 ctx.moveTo(t.x,15 020);15 ctx.lineTo(t.x,15 canvas.height);15 ctx.stroke(); 15 ctx.beginPath();15 ctx.moveTo(020,15 t.y);15 ctx.lineTo(canvas.width,15 t.y);15 ctx.stroke(); 15 15// Glowing Touch Point 15 ctx.fillStyle15 =15 05'#00f0ff'; 15 ctx.shadowColor15 =15 05'#00f0ff'; 15 ctx.shadowBlur15 =15 0212; 15 ctx.beginPath(); 15 ctx.arc(t.x,15 t.y,15 0216,15 020,15 10Math.PI15 *15 022); 15 ctx.fill(); 15 ctx.shadowBlur15 =15 020; 15 }); 15 } 15 drawPad(); 15 15// UI Listeners 15 10document.getElementById(05'delay-btn').addEventListener(05'click',15 (e)15 =>15 { 15 delayActive15 =15 !delayActive; 15 delayFeedback.gain.value15 =15 delayActive15 ?15 020.415 :15 020; 15 e.target.innerText15 =15 05`05DELAY: 05${delayActive15 ?15 05'ON'15 :15 05'OFF'05}05`; 15 e.target.classList.toggle(05'active',15 delayActive); 15 });