antigravity one shot

This commit is contained in:
2025-12-21 12:20:40 +01:00
parent 5fd7786ba3
commit f510de47d1
23 changed files with 4462 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
import { YIN } from "pitchfinder";
export class PitchAnalyzer {
private detector: (buffer: Float32Array) => number | null;
private audioContext: AudioContext | null = null;
private analyser: AnalyserNode | null = null;
private mediaStream: MediaStream | null = null;
private source: MediaStreamAudioSourceNode | null = null;
private buffer: Float32Array;
constructor() {
this.detector = YIN({ sampleRate: 44100 }); // Default, will update on start
this.buffer = new Float32Array(2048); // Standard size
}
async start(): Promise<void> {
if (this.audioContext) return;
this.audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
this.detector = YIN({ sampleRate: this.audioContext.sampleRate });
try {
this.mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
this.source = this.audioContext.createMediaStreamSource(this.mediaStream);
this.analyser = this.audioContext.createAnalyser();
this.analyser.fftSize = 4096; // Higher FFT size for better resolution at low frequencies
this.buffer = new Float32Array(this.analyser.fftSize);
this.source.connect(this.analyser);
} catch (e) {
console.error("Error accessing microphone:", e);
throw e;
}
}
stop() {
if (this.mediaStream) {
this.mediaStream.getTracks().forEach(track => track.stop());
this.mediaStream = null;
}
if (this.audioContext) {
this.audioContext.close();
this.audioContext = null;
}
}
/**
* getPitch returns the detected frequency in Hz, or null if no pitch detected
*/
getPitch(): number | null {
if (!this.analyser) return null;
this.analyser.getFloatTimeDomainData(this.buffer as any);
// Simple RMS volume check to avoid noise
let rms = 0;
for (let i = 0; i < this.buffer.length; i++) {
rms += this.buffer[i] * this.buffer[i];
}
rms = Math.sqrt(rms / this.buffer.length);
if (rms < 0.01) return null; // Silence threshold
const pitch = this.detector(this.buffer);
return pitch;
}
}