Team Ai
Apppublic

broadfield-dev/stack-overflow-game

sourceHugging Faceupdated 4mo agoView on Hugging Face
0likes
SoundGenerator.js180 linesDownload Raw Back to utils
1/**2 * Generate simple sound effects using Web Audio API3 */4export default class SoundGenerator {5  /**6   * Play a simple beep sound7   * @param {number} frequency - Frequency in Hz8   * @param {number} duration - Duration in seconds9   * @param {number} volume - Volume (0-1)10   */11  static getAudioContext() {12    if (!this.audioContext) {13      this.audioContext = new (window.AudioContext || window.webkitAudioContext)();14    }15    return this.audioContext;16  }17 18  static playBeep(frequency, duration, volume = 0.3) {19    try {20      const audioContext = this.getAudioContext();21 22      // Create oscillator23      const oscillator = audioContext.createOscillator();24      const gainNode = audioContext.createGain();25 26      oscillator.connect(gainNode);27      gainNode.connect(audioContext.destination);28 29      oscillator.frequency.value = frequency;30      oscillator.type = 'square'; // Retro square wave sound31 32      // Envelope33      gainNode.gain.setValueAtTime(volume, audioContext.currentTime);34      gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration);35 36      oscillator.start(audioContext.currentTime);37      oscillator.stop(audioContext.currentTime + duration);38    } catch (e) {39      console.warn('Audio not available:', e);40    }41  }42 43  static playMove() {44    this.playBeep(200, 0.05, 0.2);45  }46 47  static playRotate() {48    this.playBeep(300, 0.08, 0.25);49  }50 51  static playDrop() {52    this.playBeep(150, 0.15, 0.3);53  }54 55  static playLineClear(lineCount = 1) {56    // Noisy 8-bit explosion57    this.playNoisyExplosion();58 59    // Add bonus sounds for multiple lines60    if (lineCount === 2) {61      setTimeout(() => this.playBeep(600, 0.15, 0.25), 100);62      setTimeout(() => this.playBeep(800, 0.15, 0.25), 200);63    } else if (lineCount === 3) {64      setTimeout(() => this.playBeep(700, 0.12, 0.25), 100);65      setTimeout(() => this.playBeep(900, 0.12, 0.25), 180);66      setTimeout(() => this.playBeep(1100, 0.15, 0.25), 260);67    } else if (lineCount >= 4) {68      // Tetris! Extra exciting69      setTimeout(() => this.playBeep(800, 0.1, 0.3), 100);70      setTimeout(() => this.playBeep(1000, 0.1, 0.3), 180);71      setTimeout(() => this.playBeep(1200, 0.1, 0.3), 260);72      setTimeout(() => this.playBeep(1400, 0.2, 0.3), 340);73    }74  }75 76  static playNoisyExplosion() {77    try {78      const audioContext = this.getAudioContext();79 80      // Create white noise81      const bufferSize = audioContext.sampleRate * 0.5;82      const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate);83      const noiseData = noiseBuffer.getChannelData(0);84 85      for (let i = 0; i < bufferSize; i++) {86        noiseData[i] = Math.random() * 2 - 1;87      }88 89      const noise = audioContext.createBufferSource();90      noise.buffer = noiseBuffer;91 92      // Filter the noise93      const filter = audioContext.createBiquadFilter();94      filter.type = 'lowpass';95      filter.frequency.setValueAtTime(2000, audioContext.currentTime);96      filter.frequency.exponentialRampToValueAtTime(80, audioContext.currentTime + 0.5);97 98      const gainNode = audioContext.createGain();99      gainNode.gain.setValueAtTime(0.7, audioContext.currentTime);100      gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5);101 102      noise.connect(filter);103      filter.connect(gainNode);104      gainNode.connect(audioContext.destination);105 106      noise.start(audioContext.currentTime);107      noise.stop(audioContext.currentTime + 0.5);108    } catch (e) {109      console.warn('Audio not available:', e);110    }111  }112 113  static playSoftDrop() {114    this.playBeep(120, 0.04, 0.15);115  }116 117  static playTetris() {118    // Exciting sound for 4-line clear119    this.playBeep(500, 0.1, 0.35);120    setTimeout(() => this.playBeep(600, 0.1, 0.35), 60);121    setTimeout(() => this.playBeep(700, 0.1, 0.35), 120);122    setTimeout(() => this.playBeep(800, 0.2, 0.35), 180);123  }124 125  static playLevelUp() {126    // Ascending tone127    this.playBeep(400, 0.1, 0.3);128    setTimeout(() => this.playBeep(500, 0.1, 0.3), 80);129    setTimeout(() => this.playBeep(600, 0.1, 0.3), 160);130    setTimeout(() => this.playBeep(700, 0.2, 0.3), 240);131  }132 133  static playGameOver() {134    // Descending tone135    this.playBeep(400, 0.15, 0.3);136    setTimeout(() => this.playBeep(300, 0.15, 0.3), 120);137    setTimeout(() => this.playBeep(200, 0.15, 0.3), 240);138    setTimeout(() => this.playBeep(100, 0.3, 0.3), 360);139  }140 141  static playWoosh() {142    try {143      const audioContext = this.getAudioContext();144 145      // Create white noise for woosh effect146      const bufferSize = audioContext.sampleRate * 0.4;147      const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate);148      const noiseData = noiseBuffer.getChannelData(0);149 150      for (let i = 0; i < bufferSize; i++) {151        noiseData[i] = Math.random() * 2 - 1;152      }153 154      const noise = audioContext.createBufferSource();155      noise.buffer = noiseBuffer;156 157      // High-pass filter for airy woosh sound158      const filter = audioContext.createBiquadFilter();159      filter.type = 'highpass';160      filter.frequency.setValueAtTime(800, audioContext.currentTime);161      filter.frequency.exponentialRampToValueAtTime(200, audioContext.currentTime + 0.4);162 163      const gainNode = audioContext.createGain();164      gainNode.gain.setValueAtTime(0.4, audioContext.currentTime);165      gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.4);166 167      noise.connect(filter);168      filter.connect(gainNode);169      gainNode.connect(audioContext.destination);170 171      noise.start(audioContext.currentTime);172      noise.stop(audioContext.currentTime + 0.4);173    } catch (e) {174      console.warn('Audio not available:', e);175    }176  }177}178 179 180