<! DOCTYPE html >
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title >Advanced Voice Recorder</ title >
< style >
body {
font-family : Arial , sans-serif ;
background-color : #f0f4f8 ;
display : flex ;
justify-content : center ;
align-items : center ;
height : 100 vh ;
margin : 0 ;
}
.container {
text-align : center ;
background-color : #ffffff ;
padding : 30 px ;
border-radius : 15 px ;
box-shadow : 0 4 px 10 px rgba ( 0 , 0 , 0 , 0.1 );
}
h1 {
color : #333 ;
margin-bottom : 20 px ;
}
.recorder {
margin : 20 px 0 ;
}
.btn {
background-color : #007bff ;
color : #fff ;
border : none ;
padding : 12 px 24 px ;
margin : 10 px ;
border-radius : 5 px ;
cursor : pointer ;
font-size : 16 px ;
transition : background-color 0.3 s ease ;
}
.btn:hover:not ( :disabled ) {
background-color : #0056b3 ;
}
.btn:disabled {
background-color : #cccccc ;
cursor : not-allowed ;
}
.effect-select {
margin-top : 20 px ;
padding : 10 px ;
font-size : 16 px ;
border-radius : 5 px ;
border : 1 px solid #cccccc ;
cursor : pointer ;
}
audio {
margin-top : 20 px ;
width : 100 % ;
max-width : 300 px ;
outline : none ;
}
.visualizer {
margin-top : 20 px ;
height : 100 px ;
width : 100 % ;
background-color : #e9ecef ;
border-radius : 5 px ;
overflow : hidden ;
}
canvas {
width : 100 % ;
height : 100 % ;
}
</ style >
</ head >
< body >
< div class = "container" >
< h1 >Advanced Voice Recorder</ h1 >
< div class = "recorder" >
< button id = "recordBtn" class = "btn" >🎤 Start Recording</ button >
< button id = "stopBtn" class = "btn" disabled >🛑 Stop Recording</ button >
< button id = "downloadBtn" class = "btn" disabled >📥 Download MP3</ button >
</ div >
< div class = "effects" >
< h2 >Voice Effects</ h2 >
< select id = "effectSelector" class = "effect-select" >
< option value = "none" >None</ option >
< option value = "robot" >Robot</ option >
< option value = "chipmunk" >Chipmunk</ option >
< option value = "alien" >Alien</ option >
< option value = "dog" >Dog</ option >
< option value = "cat" >Cat</ option >
</ select >
</ div >
< div class = "visualizer" >
< canvas id = "visualizerCanvas" ></ canvas >
</ div >
< audio id = "audioPlayer" controls ></ audio >
</ div >
< script >
let chunks = [];
let recorder;
let audioBlob;
let audioContext;
let sourceNode;
let gainNode;
let scriptProcessorNode;
let analyserNode;
let audioData = [];
let effect = 'none' ;
const recordBtn = document. getElementById ( 'recordBtn' );
const stopBtn = document. getElementById ( 'stopBtn' );
const downloadBtn = document. getElementById ( 'downloadBtn' );
const effectSelector = document. getElementById ( 'effectSelector' );
const audioPlayer = document. getElementById ( 'audioPlayer' );
const visualizerCanvas = document. getElementById ( 'visualizerCanvas' );
const canvasContext = visualizerCanvas. getContext ( '2d' );
recordBtn. addEventListener ( 'click' , startRecording);
stopBtn. addEventListener ( 'click' , stopRecording);
downloadBtn. addEventListener ( 'click' , downloadRecording);
effectSelector. addEventListener ( 'change' , () => {
effect = effectSelector.value;
});
function startRecording () {
navigator.mediaDevices. getUserMedia ({ audio: true })
. then ( stream => {
audioContext = new AudioContext ();
sourceNode = audioContext. createMediaStreamSource (stream);
gainNode = audioContext. createGain ();
analyserNode = audioContext. createAnalyser ();
scriptProcessorNode = audioContext. createScriptProcessor ( 4096 , 1 , 1 );
sourceNode. connect (gainNode);
gainNode. connect (analyserNode);
analyserNode. connect (scriptProcessorNode);
scriptProcessorNode. connect (audioContext.destination);
scriptProcessorNode.onaudioprocess = processAudioData;
recorder = new MediaRecorder (stream);
recorder. ondataavailable = event => chunks. push (event.data);
recorder.onstop = createAudioBlob;
recorder. start ();
visualizeAudio ();
recordBtn.disabled = true ;
stopBtn.disabled = false ;
downloadBtn.disabled = true ;
});
}
function stopRecording () {
recorder. stop ();
stopBtn.disabled = true ;
recordBtn.disabled = false ;
}
function createAudioBlob () {
audioBlob = new Blob (chunks, { type: 'audio/mp3' });
chunks = [];
const audioUrl = URL . createObjectURL (audioBlob);
audioPlayer.src = audioUrl;
downloadBtn.disabled = false ;
}
function downloadRecording () {
const link = document. createElement ( 'a' );
link.href = URL . createObjectURL (audioBlob);
link.download = 'recording.mp3' ;
link. click ();
}
function processAudioData ( event ) {
audioData = event.inputBuffer. getChannelData ( 0 );
switch (effect) {
case 'robot' :
applyRobotEffect (audioData);
break ;
case 'chipmunk' :
applyChipmunkEffect (audioData);
break ;
case 'alien' :
applyAlienEffect (audioData);
break ;
case 'dog' :
applyDogEffect (audioData);
break ;
case 'cat' :
applyCatEffect (audioData);
break ;
default :
break ;
}
}
function applyRobotEffect ( data ) {
for ( let i = 0 ; i < data. length ; i ++ ) {
data[i] = Math. sign (data[i]) * Math. sqrt (Math. abs (data[i]));
}
}
function applyChipmunkEffect ( data ) {
for ( let i = 0 ; i < data. length ; i ++ ) {
data[i] *= 2 ;
}
}
function applyAlienEffect ( data ) {
for ( let i = 0 ; i < data. length ; i ++ ) {
data[i] = Math. sin ( 2 * Math. PI * 440 * data[i]);
}
}
function applyDogEffect ( data ) {
for ( let i = 0 ; i < data. length ; i ++ ) {
data[i] *= 0.5 ;
}
}
function applyCatEffect ( data ) {
for ( let i = 0 ; i < data. length ; i ++ ) {
data[i] = Math. tanh (data[i]);
}
}
function visualizeAudio () {
analyserNode.fftSize = 2048 ;
const bufferLength = analyserNode.frequencyBinCount;
const dataArray = new Uint8Array (bufferLength);
function draw () {
requestAnimationFrame (draw);
analyserNode. getByteTimeDomainData (dataArray);
canvasContext.fillStyle = '#e9ecef' ;
canvasContext. fillRect ( 0 , 0 , visualizerCanvas.width, visualizerCanvas.height);
canvasContext.lineWidth = 2 ;
canvasContext.strokeStyle = '#007bff' ;
canvasContext. beginPath ();
const sliceWidth = visualizerCanvas.width * 1.0 / bufferLength;
let x = 0 ;
for ( let i = 0 ; i < bufferLength; i ++ ) {
const v = dataArray[i] / 128.0 ;
const y = v * visualizerCanvas.height / 2 ;
if (i === 0 ) {
canvasContext. moveTo (x, y);
} else {
canvasContext. lineTo (x, y);
}
x += sliceWidth;
}
canvasContext. lineTo (visualizerCanvas.width, visualizerCanvas.height / 2 );
canvasContext. stroke ();
}
draw ();
}
</ script >
</ body >
</ html >
HTML