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 Synth12title>
<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 12style>
12head>
<12body>
<12div 10class=05"header">
<12div 10class=05"title">KITARA-MOBILE12div>
<12div 10class=05"status" 10id=05"status-display">TOUCH PAD TO PLAY12div>
12div>
<12div 10class=05"fretboard-container" 10id=05"fretboard">12div>
<12div 10class=05"pad-container" 10id=05"pad-box">
<12canvas 10id=05"pad-canvas">12canvas>
12div>
<12div 10class=05"controls-bar">
<12select 10id=05"synth-sound">
<12option 10value=05"lead">Kitara Cyber Lead12option>
<12option 10value=05"acid">303 Distorted12option>
<12option 10value=05"poly">Digital PolySaw12option>
<12option 10value=05"sub">Sub Bass Heavy12option>
12select>
<12button 10id=05"delay-btn">DELAY: ON12button>
12div>
<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 });
12script>
12body>
12html>