kolaslab's picture
Update index.html
797cfe7 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Multi-Device Audio Analysis System</title>
<style>
:root {
--primary: #2196F3;
--secondary: #4CAF50;
--bg-dark: #1a1a1a;
--bg-light: #2a2a2a;
--text: #ffffff;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', system-ui, sans-serif;
}
body {
background: var(--bg-dark);
color: var(--text);
min-height: 100vh;
}
.app-container {
display: grid;
grid-template-columns: 300px 1fr;
gap: 20px;
padding: 20px;
height: 100vh;
}
.sidebar {
background: var(--bg-light);
border-radius: 12px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 20px;
}
.main-content {
display: grid;
grid-template-rows: auto 1fr;
gap: 20px;
}
.visualization-container {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 20px;
}
.canvas-container {
background: var(--bg-light);
border-radius: 12px;
padding: 20px;
position: relative;
}
canvas {
width: 100%;
height: 100%;
background: rgba(0,0,0,0.2);
border-radius: 8px;
}
.control-panel {
background: var(--bg-light);
border-radius: 12px;
padding: 20px;
}
.btn {
background: var(--primary);
color: white;
border: none;
padding: 12px 24px;
border-radius: 6px;
cursor: pointer;
transition: opacity 0.2s;
width: 100%;
margin-bottom: 10px;
}
.btn:hover {
opacity: 0.9;
}
.btn.secondary {
background: var(--secondary);
}
.input-group {
margin-bottom: 15px;
}
.input-group label {
display: block;
margin-bottom: 5px;
color: #888;
}
input[type="number"],
select {
width: 100%;
padding: 8px;
background: rgba(255,255,255,0.1);
border: 1px solid rgba(255,255,255,0.2);
border-radius: 4px;
color: white;
}
.device-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.device-item {
background: rgba(255,255,255,0.1);
padding: 10px;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}
.status-indicator {
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--secondary);
}
#frequencyDisplay {
position: absolute;
top: 10px;
right: 10px;
background: rgba(0,0,0,0.7);
padding: 5px 10px;
border-radius: 4px;
}
.preset-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 10px;
}
.preset-item {
background: rgba(255,255,255,0.1);
padding: 10px;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s;
}
.preset-item:hover {
background: rgba(255,255,255,0.2);
}
</style>
</head>
<body>
<div class="app-container">
<aside class="sidebar">
<div class="control-panel">
<h3>Device Settings</h3>
<div class="input-group">
<label>Device Role</label>
<select id="deviceRole">
<option value="primary">Primary</option>
<option value="left">Left Channel</option>
<option value="right">Right Channel</option>
</select>
</div>
<button class="btn" id="startCapture">Start Capture</button>
<button class="btn secondary" id="calibrate">Calibrate</button>
</div>
<div class="device-list">
<h3>Connected Devices</h3>
<div class="device-item">
<span>This Device</span>
<div class="status-indicator"></div>
</div>
</div>
</aside>
<main class="main-content">
<div class="control-panel">
<h2>Binaural Beat Generator</h2>
<div class="input-group">
<label>Base Frequency (Hz)</label>
<input type="number" id="baseFreq" value="432" min="20" max="1000">
</div>
<div class="input-group">
<label>Beat Frequency (Hz)</label>
<input type="number" id="beatFreq" value="7" min="1" max="40">
</div>
<button class="btn" id="generateBeat">Generate Beat</button>
</div>
<div class="visualization-container">
<div class="canvas-container">
<canvas id="spectrumAnalyzer"></canvas>
<div id="frequencyDisplay">0 Hz</div>
</div>
<div class="canvas-container">
<canvas id="roomAnalysis"></canvas>
</div>
</div>
</main>
</div>
<script>
class AudioSystem {
constructor() {
this.audioContext = null;
this.analyser = null;
this.gainNode = null;
this.oscillators = {};
this.isCapturing = false;
this.isGenerating = false;
this.initialize();
this.setupEventListeners();
}
async initialize() {
try {
this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
this.analyser = this.audioContext.createAnalyser();
this.gainNode = this.audioContext.createGain();
this.analyser.fftSize = 2048;
this.gainNode.connect(this.audioContext.destination);
this.analyser.connect(this.gainNode);
await this.setupSpectrumVisualizer();
} catch (error) {
console.error('Audio initialization failed:', error);
}
}
async startCapture() {
if (this.isCapturing) return;
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const source = this.audioContext.createMediaStreamSource(stream);
source.connect(this.analyser);
this.isCapturing = true;
} catch (error) {
console.error('Capture failed:', error);
}
}
generateBinauralBeat(baseFreq, beatFreq) {
if (this.isGenerating) this.stopBinauralBeat();
const leftOsc = this.audioContext.createOscillator();
const rightOsc = this.audioContext.createOscillator();
leftOsc.frequency.value = baseFreq;
rightOsc.frequency.value = baseFreq + beatFreq;
const merger = this.audioContext.createChannelMerger(2);
leftOsc.connect(merger, 0, 0);
rightOsc.connect(merger, 0, 1);
merger.connect(this.gainNode);
leftOsc.start();
rightOsc.start();
this.oscillators = { left: leftOsc, right: rightOsc };
this.isGenerating = true;
}
stopBinauralBeat() {
if (!this.isGenerating) return;
Object.values(this.oscillators).forEach(osc => osc.stop());
this.oscillators = {};
this.isGenerating = false;
}
async setupSpectrumVisualizer() {
const canvas = document.getElementById('spectrumAnalyzer');
const ctx = canvas.getContext('2d');
const bufferLength = this.analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const draw = () => {
requestAnimationFrame(draw);
this.analyser.getByteFrequencyData(dataArray);
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
const barWidth = canvas.width / bufferLength;
let x = 0;
for(let i = 0; i < bufferLength; i++) {
const barHeight = (dataArray[i] / 255) * canvas.height;
const hue = i / bufferLength * 360;
ctx.fillStyle = `hsl(${hue}, 100%, 50%)`;
ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
};
draw();
}
setupEventListeners() {
document.getElementById('startCapture').onclick = () => this.startCapture();
document.getElementById('generateBeat').onclick = () => {
const baseFreq = parseFloat(document.getElementById('baseFreq').value);
const beatFreq = parseFloat(document.getElementById('beatFreq').value);
this.generateBinauralBeat(baseFreq, beatFreq);
};
}
}
// Initialize the system
const audioSystem = new AudioSystem();
</script>
</body>
</html><script async data-explicit-opt-in="true" data-cookie-opt-in="true" src="https://vercel.live/_next-live/feedback/feedback.js"></script>