|
|
@@ -123,78 +123,105 @@ class DawdlehornApp {
|
|
|
}
|
|
|
|
|
|
handleGamepadInput(gamepad) {
|
|
|
- // Update debug displays FIRST - this shows raw input immediately
|
|
|
- const leftStickX = gamepad.axes[0] || 0;
|
|
|
- const leftStickY = gamepad.axes[1] || 0;
|
|
|
- const rightStickX = gamepad.axes[2] || 0;
|
|
|
- const rightStickY = gamepad.axes[3] || 0;
|
|
|
-
|
|
|
- this.elements.leftStickDisplay.textContent = `${leftStickX.toFixed(2)}, ${leftStickY.toFixed(2)}`;
|
|
|
- this.elements.rightStickDisplay.textContent = `${rightStickX.toFixed(2)}, ${rightStickY.toFixed(2)}`;
|
|
|
-
|
|
|
- const leftTrigger = gamepad.buttons[6] ? gamepad.buttons[6].value : 0;
|
|
|
- const rightTrigger = gamepad.buttons[7] ? gamepad.buttons[7].value : 0;
|
|
|
- this.elements.triggersDisplay.textContent = `L: ${leftTrigger.toFixed(2)} R: ${rightTrigger.toFixed(2)}`;
|
|
|
-
|
|
|
- const buttonA = gamepad.buttons[0] && gamepad.buttons[0].pressed;
|
|
|
- const buttonB = gamepad.buttons[1] && gamepad.buttons[1].pressed;
|
|
|
- const buttonX = gamepad.buttons[2] && gamepad.buttons[2].pressed;
|
|
|
- const buttonY = gamepad.buttons[3] && gamepad.buttons[3].pressed;
|
|
|
-
|
|
|
- let buttonDisplay = '';
|
|
|
- buttonDisplay += buttonA ? '[A]' : 'A';
|
|
|
- buttonDisplay += ' ';
|
|
|
- buttonDisplay += buttonB ? '[B]' : 'B';
|
|
|
- buttonDisplay += ' ';
|
|
|
- buttonDisplay += buttonX ? '[X]' : 'X';
|
|
|
- buttonDisplay += ' ';
|
|
|
- buttonDisplay += buttonY ? '[Y]' : 'Y';
|
|
|
- this.elements.buttonsDisplay.textContent = buttonDisplay;
|
|
|
-
|
|
|
- // Early return if audio not ready
|
|
|
- if (!this.audioInitialized) return;
|
|
|
-
|
|
|
- // Left stick X-axis controls frequency (200Hz - 2000Hz)
|
|
|
- const newFreq = 440 + (leftStickX * 560); // 440Hz ± 560Hz
|
|
|
- if (Math.abs(newFreq - this.currentFreq) > 5) {
|
|
|
- this.currentFreq = newFreq;
|
|
|
- this.synth.frequency.setValueAtTime(this.currentFreq, Tone.now());
|
|
|
- this.elements.freqDisplay.textContent = `${Math.round(this.currentFreq)} Hz`;
|
|
|
- }
|
|
|
+ try {
|
|
|
+ // Update debug displays FIRST - this shows raw input immediately
|
|
|
+ // Standard gamepad mapping: axes[0]=left stick X, axes[1]=left stick Y, axes[2]=right stick X, axes[3]=right stick Y
|
|
|
+ const leftStickX = gamepad.axes[0] || 0;
|
|
|
+ const leftStickY = gamepad.axes[1] || 0;
|
|
|
+ const rightStickX = gamepad.axes[2] || 0;
|
|
|
+ const rightStickY = gamepad.axes[3] || 0;
|
|
|
+
|
|
|
+ this.elements.leftStickDisplay.textContent = `${leftStickX.toFixed(2)}, ${leftStickY.toFixed(2)}`;
|
|
|
+ this.elements.rightStickDisplay.textContent = `${rightStickX.toFixed(2)}, ${rightStickY.toFixed(2)}`;
|
|
|
+
|
|
|
+ // Triggers: L2=buttons[6], R2=buttons[7] (analog values)
|
|
|
+ const leftTrigger = gamepad.buttons[6] ? gamepad.buttons[6].value : 0;
|
|
|
+ const rightTrigger = gamepad.buttons[7] ? gamepad.buttons[7].value : 0;
|
|
|
+ this.elements.triggersDisplay.textContent = `L: ${leftTrigger.toFixed(2)} R: ${rightTrigger.toFixed(2)}`;
|
|
|
+
|
|
|
+ // Face buttons: A=0, B=1, X=2, Y=3
|
|
|
+ const buttonA = gamepad.buttons[0] && gamepad.buttons[0].pressed;
|
|
|
+ const buttonB = gamepad.buttons[1] && gamepad.buttons[1].pressed;
|
|
|
+ const buttonX = gamepad.buttons[2] && gamepad.buttons[2].pressed;
|
|
|
+ const buttonY = gamepad.buttons[3] && gamepad.buttons[3].pressed;
|
|
|
+
|
|
|
+ let buttonDisplay = '';
|
|
|
+ buttonDisplay += buttonA ? '[A]' : 'A';
|
|
|
+ buttonDisplay += ' ';
|
|
|
+ buttonDisplay += buttonB ? '[B]' : 'B';
|
|
|
+ buttonDisplay += ' ';
|
|
|
+ buttonDisplay += buttonX ? '[X]' : 'X';
|
|
|
+ buttonDisplay += ' ';
|
|
|
+ buttonDisplay += buttonY ? '[Y]' : 'Y';
|
|
|
+ this.elements.buttonsDisplay.textContent = buttonDisplay;
|
|
|
+
|
|
|
+ // Early return if audio not ready
|
|
|
+ if (!this.audioInitialized) return;
|
|
|
+
|
|
|
+ // Left stick X-axis controls frequency (200Hz - 2000Hz)
|
|
|
+ const newFreq = 440 + (leftStickX * 560); // 440Hz ± 560Hz
|
|
|
+ if (Math.abs(newFreq - this.currentFreq) > 5) {
|
|
|
+ this.currentFreq = newFreq;
|
|
|
+ this.synth.frequency.setValueAtTime(this.currentFreq, Tone.now());
|
|
|
+ this.elements.freqDisplay.textContent = `${Math.round(this.currentFreq)} Hz`;
|
|
|
+ }
|
|
|
|
|
|
- // Right stick Y-axis controls filter frequency (100Hz - 5000Hz)
|
|
|
- const newFilter = 1000 + (rightStickY * -2000); // Inverted Y, 1000Hz ± 2000Hz
|
|
|
- if (Math.abs(newFilter - this.currentFilter) > 50) {
|
|
|
- this.currentFilter = Math.max(100, Math.min(5000, newFilter));
|
|
|
- this.filter.frequency.setValueAtTime(this.currentFilter, Tone.now());
|
|
|
- this.elements.filterDisplay.textContent = `${Math.round(this.currentFilter)} Hz`;
|
|
|
- }
|
|
|
+ // Right stick Y-axis controls filter frequency (100Hz - 5000Hz)
|
|
|
+ const newFilter = 1000 + (rightStickY * -2000); // Inverted Y, 1000Hz ± 2000Hz
|
|
|
+ if (Math.abs(newFilter - this.currentFilter) > 50) {
|
|
|
+ this.currentFilter = Math.max(100, Math.min(5000, newFilter));
|
|
|
+ this.filter.frequency.setValueAtTime(this.currentFilter, Tone.now());
|
|
|
+ this.elements.filterDisplay.textContent = `${Math.round(this.currentFilter)} Hz`;
|
|
|
+ }
|
|
|
|
|
|
- // Triggers control volume
|
|
|
- const triggerVolume = (leftTrigger + rightTrigger) / 2;
|
|
|
- if (Math.abs(triggerVolume - this.currentVolume) > 0.05) {
|
|
|
- this.currentVolume = triggerVolume;
|
|
|
- const dbVolume = -40 + (this.currentVolume * 40); // -40dB to 0dB
|
|
|
- this.volume.volume.setValueAtTime(dbVolume, Tone.now());
|
|
|
- this.elements.volumeDisplay.textContent = `${Math.round(this.currentVolume * 100)}%`;
|
|
|
- }
|
|
|
+ // Triggers control volume
|
|
|
+ const triggerVolume = (leftTrigger + rightTrigger) / 2;
|
|
|
+ if (Math.abs(triggerVolume - this.currentVolume) > 0.05) {
|
|
|
+ this.currentVolume = triggerVolume;
|
|
|
+ const dbVolume = -40 + (this.currentVolume * 40); // -40dB to 0dB
|
|
|
+ this.volume.volume.setValueAtTime(dbVolume, Tone.now());
|
|
|
+ this.elements.volumeDisplay.textContent = `${Math.round(this.currentVolume * 100)}%`;
|
|
|
+ }
|
|
|
|
|
|
- // Face buttons control note playing
|
|
|
- const anyButtonPressed = buttonA || buttonB || buttonX || buttonY;
|
|
|
+ // Face buttons control note playing
|
|
|
+ const anyButtonPressed = buttonA || buttonB || buttonX || buttonY;
|
|
|
|
|
|
- if (anyButtonPressed && !this.isPlaying) {
|
|
|
- this.synth.start();
|
|
|
- this.isPlaying = true;
|
|
|
- } else if (!anyButtonPressed && this.isPlaying) {
|
|
|
- this.synth.stop();
|
|
|
- this.isPlaying = false;
|
|
|
- }
|
|
|
+ if (anyButtonPressed && !this.isPlaying) {
|
|
|
+ this.synth.start();
|
|
|
+ this.isPlaying = true;
|
|
|
+ } else if (!anyButtonPressed && this.isPlaying) {
|
|
|
+ this.synth.stop();
|
|
|
+ this.isPlaying = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Different buttons trigger different note frequencies
|
|
|
+ if (buttonA) this.synth.frequency.setValueAtTime(261.63, Tone.now()); // C4
|
|
|
+ if (buttonB) this.synth.frequency.setValueAtTime(293.66, Tone.now()); // D4
|
|
|
+ if (buttonX) this.synth.frequency.setValueAtTime(329.63, Tone.now()); // E4
|
|
|
+ if (buttonY) this.synth.frequency.setValueAtTime(349.23, Tone.now()); // F4
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ console.error('❌ Gamepad input error:', error);
|
|
|
+
|
|
|
+ // Emergency stop audio on any error
|
|
|
+ if (this.isPlaying && this.synth) {
|
|
|
+ try {
|
|
|
+ this.synth.stop();
|
|
|
+ this.isPlaying = false;
|
|
|
+ } catch (stopError) {
|
|
|
+ console.error('❌ Failed to stop synth:', stopError);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // Different buttons trigger different note frequencies
|
|
|
- if (buttonA) this.synth.frequency.setValueAtTime(261.63, Tone.now()); // C4
|
|
|
- if (buttonB) this.synth.frequency.setValueAtTime(293.66, Tone.now()); // D4
|
|
|
- if (buttonX) this.synth.frequency.setValueAtTime(329.63, Tone.now()); // E4
|
|
|
- if (buttonY) this.synth.frequency.setValueAtTime(349.23, Tone.now()); // F4
|
|
|
+ // Update UI to show error state
|
|
|
+ this.elements.buttonsDisplay.textContent = 'ERROR - Audio Stopped';
|
|
|
+ this.elements.buttonsDisplay.style.color = '#ff0000';
|
|
|
+
|
|
|
+ // Reset error state after 2 seconds
|
|
|
+ setTimeout(() => {
|
|
|
+ this.elements.buttonsDisplay.style.color = '#00ff00';
|
|
|
+ }, 2000);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
setupVisualizer() {
|