Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Random Binaural Beat Generator</title> | |
<style> | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
} | |
body { | |
background: linear-gradient(45deg, #1a1a1a, #2d2d2d); | |
color: #fff; | |
min-height: 100vh; | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
padding: 2rem; | |
} | |
.container { | |
max-width: 800px; | |
width: 100%; | |
background: rgba(255, 255, 255, 0.1); | |
padding: 2rem; | |
border-radius: 15px; | |
backdrop-filter: blur(10px); | |
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); | |
} | |
h1 { | |
text-align: center; | |
margin-bottom: 2rem; | |
color: #00ff88; | |
text-shadow: 0 0 10px rgba(0, 255, 136, 0.5); | |
} | |
.controls { | |
display: grid; | |
gap: 1.5rem; | |
margin-bottom: 2rem; | |
} | |
.control-group { | |
display: flex; | |
flex-direction: column; | |
gap: 0.5rem; | |
} | |
label { | |
font-size: 1.1rem; | |
color: #00ff88; | |
} | |
input[type="range"] { | |
width: 100%; | |
height: 10px; | |
background: rgba(255, 255, 255, 0.1); | |
border-radius: 5px; | |
outline: none; | |
-webkit-appearance: none; | |
} | |
input[type="range"]::-webkit-slider-thumb { | |
-webkit-appearance: none; | |
width: 20px; | |
height: 20px; | |
background: #00ff88; | |
border-radius: 50%; | |
cursor: pointer; | |
transition: background 0.3s; | |
} | |
.value-display { | |
font-size: 1.2rem; | |
color: #fff; | |
text-align: center; | |
} | |
.buttons { | |
display: flex; | |
gap: 1rem; | |
justify-content: center; | |
} | |
button { | |
padding: 1rem 2rem; | |
font-size: 1.1rem; | |
border: none; | |
border-radius: 5px; | |
background: #00ff88; | |
color: #1a1a1a; | |
cursor: pointer; | |
transition: all 0.3s; | |
} | |
button:hover { | |
background: #00cc6a; | |
transform: translateY(-2px); | |
} | |
.display { | |
margin-top: 2rem; | |
padding: 1rem; | |
background: rgba(0, 255, 136, 0.1); | |
border-radius: 10px; | |
text-align: center; | |
} | |
#currentFrequencies { | |
font-size: 1.5rem; | |
color: #00ff88; | |
margin: 1rem 0; | |
line-height: 1.6; | |
} | |
.wave-visualizer { | |
width: 100%; | |
height: 100px; | |
background: rgba(255, 255, 255, 0.05); | |
margin-top: 2rem; | |
border-radius: 5px; | |
overflow: hidden; | |
position: relative; | |
} | |
.wave { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
background: linear-gradient(180deg, transparent 0%, #00ff88 50%, transparent 100%); | |
opacity: 0.3; | |
animation: wave 2s infinite linear; | |
} | |
@keyframes wave { | |
0% { transform: translateX(-100%) scaleY(0.5); } | |
50% { transform: translateX(0%) scaleY(1); } | |
100% { transform: translateX(100%) scaleY(0.5); } | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>Random Binaural Beat Generator</h1> | |
<div class="controls"> | |
<div class="control-group"> | |
<label for="beatFrequency">Target Beat Frequency (Hz)</label> | |
<input type="range" id="beatFrequency" min="1" max="40" value="7.83"> | |
<div class="value-display" id="beatFrequencyValue">7.83 Hz</div> | |
</div> | |
<div class="control-group"> | |
<label for="interval">Interval Between Changes (ms)</label> | |
<input type="range" id="interval" min="100" max="2000" value="500"> | |
<div class="value-display" id="intervalValue">500 ms</div> | |
</div> | |
<div class="control-group"> | |
<label for="volume">Volume</label> | |
<input type="range" id="volume" min="0" max="1" step="0.1" value="0.5"> | |
<div class="value-display" id="volumeValue">50%</div> | |
</div> | |
</div> | |
<div class="buttons"> | |
<button id="startBtn">Start</button> | |
<button id="stopBtn">Stop</button> | |
</div> | |
<div class="display"> | |
<p>Current Frequencies:</p> | |
<div id="currentFrequencies"> | |
Left: 0 Hz<br> | |
Right: 0 Hz<br> | |
Beat: 0 Hz | |
</div> | |
</div> | |
<div class="wave-visualizer"> | |
<div class="wave"></div> | |
</div> | |
</div> | |
<script> | |
let audioContext; | |
let oscillatorLeft; | |
let oscillatorRight; | |
let gainNode; | |
let isPlaying = false; | |
let intervalId; | |
const startBtn = document.getElementById('startBtn'); | |
const stopBtn = document.getElementById('stopBtn'); | |
const beatFrequencySlider = document.getElementById('beatFrequency'); | |
const intervalSlider = document.getElementById('interval'); | |
const volumeSlider = document.getElementById('volume'); | |
const currentFrequenciesDisplay = document.getElementById('currentFrequencies'); | |
function updateValueDisplays() { | |
document.getElementById('beatFrequencyValue').textContent = `${beatFrequencySlider.value} Hz`; | |
document.getElementById('intervalValue').textContent = `${intervalSlider.value} ms`; | |
document.getElementById('volumeValue').textContent = `${Math.round(volumeSlider.value * 100)}%`; | |
} | |
function getRandomBaseFrequency() { | |
// Random frequency between 100 and 400 Hz | |
return Math.random() * 300 + 100; | |
} | |
function initAudio() { | |
audioContext = new (window.AudioContext || window.webkitAudioContext)(); | |
gainNode = audioContext.createGain(); | |
gainNode.connect(audioContext.destination); | |
oscillatorLeft = audioContext.createOscillator(); | |
oscillatorRight = audioContext.createOscillator(); | |
const merger = audioContext.createChannelMerger(2); | |
oscillatorLeft.connect(merger, 0, 0); | |
oscillatorRight.connect(merger, 0, 1); | |
merger.connect(gainNode); | |
updateFrequencies(); | |
updateVolume(); | |
} | |
function updateFrequencies() { | |
const beatFreq = parseFloat(beatFrequencySlider.value); | |
const baseFreq = getRandomBaseFrequency(); | |
// Ensure both frequencies create the desired beat frequency | |
const leftFreq = baseFreq; | |
const rightFreq = baseFreq + beatFreq; | |
oscillatorLeft.frequency.setValueAtTime(leftFreq, audioContext.currentTime); | |
oscillatorRight.frequency.setValueAtTime(rightFreq, audioContext.currentTime); | |
currentFrequenciesDisplay.innerHTML = ` | |
Left: ${leftFreq.toFixed(2)} Hz<br> | |
Right: ${rightFreq.toFixed(2)} Hz<br> | |
Beat: ${beatFreq.toFixed(2)} Hz | |
`; | |
} | |
function updateVolume() { | |
gainNode.gain.setValueAtTime(volumeSlider.value, audioContext.currentTime); | |
} | |
function startRandomization() { | |
intervalId = setInterval(() => { | |
updateFrequencies(); | |
}, parseFloat(intervalSlider.value)); | |
} | |
startBtn.addEventListener('click', () => { | |
if (!isPlaying) { | |
initAudio(); | |
oscillatorLeft.start(); | |
oscillatorRight.start(); | |
startRandomization(); | |
isPlaying = true; | |
} | |
}); | |
stopBtn.addEventListener('click', () => { | |
if (isPlaying) { | |
clearInterval(intervalId); | |
oscillatorLeft.stop(); | |
oscillatorRight.stop(); | |
audioContext.close(); | |
isPlaying = false; | |
currentFrequenciesDisplay.innerHTML = ` | |
Left: 0 Hz<br> | |
Right: 0 Hz<br> | |
Beat: 0 Hz | |
`; | |
} | |
}); | |
beatFrequencySlider.addEventListener('input', () => { | |
updateValueDisplays(); | |
if (isPlaying) updateFrequencies(); | |
}); | |
intervalSlider.addEventListener('input', () => { | |
updateValueDisplays(); | |
if (isPlaying) { | |
clearInterval(intervalId); | |
startRandomization(); | |
} | |
}); | |
volumeSlider.addEventListener('input', () => { | |
updateValueDisplays(); | |
if (isPlaying) updateVolume(); | |
}); | |
updateValueDisplays(); | |
</script> | |
</body> | |
</html> |