Skip to content

Commit

Permalink
implemented noise supression; minor bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jsalsman committed Nov 24, 2023
1 parent a24a6b4 commit e0cbb6e
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 18 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ github: https://github.com/jsalsman/webrec
MIT license

# To do
- Microphone noiseSupression and maybe autoGainControl
- Check back about errors (warnings?) from ort.js during vad.micVAD.new()
2 changes: 1 addition & 1 deletion templates/playback.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8">
<title>Playback Audio</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="/static/recbutton.jpg">
<link rel="icon" href="/static/microphone.html">
</head>
<body>
<h1>Playback Recorded Audio</h1>
Expand Down
69 changes: 53 additions & 16 deletions templates/record.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<!DOCTYPE html>
<html lang="en">

<!--
webrec: Record and Upload Audio with Stop on Silence
Expand All @@ -27,7 +26,6 @@
github: https://github.com/jsalsman/webrec
-->

<head>
<meta charset="UTF-8">
<title>webrec: Record and Upload Audio</title>
Expand Down Expand Up @@ -148,6 +146,12 @@ <h3>Apple Safari users: <a
href="https://support.apple.com/guide/mac-help/control-access-to-the-microphone-on-mac-mchla1b1e1fe/mac"
>please see here if you are having trouble.</a></h3>
</div>

<br>
<div style="font-size: 120%">
<label><input type="checkbox" id="suppressNoise"> Noise supression
(may degrade quality)</label>
</div>

<script>
// Define global variables for audio context, stream, recorder, voice activity detection (VAD), and timeout handling
Expand Down Expand Up @@ -236,19 +240,23 @@ <h3>Apple Safari users: <a
clearTimeout(stopped_speaking_timeout);
}
}

// Event listener for the noise suppression checkbox
document.getElementById('suppressNoise').addEventListener('change', setNoiseSuppression);

}

// Function to initialize the audio recorder
async function initRecorder() {
try {
// Use the WebRTC getUserMedia API to access the user's microphone
stream = await navigator.mediaDevices.getUserMedia(
{ audio: {
noiseSuppression: false, // Optional: try noise suppression; TODO: try!
autoGainControl: false, // Optional: try automatic gain control
latency: 0, // Optional: set latency (???)
echoCancellation: false }, // Optional: set echo cancellation
video: false }); // No video is required
{ audio: { // Set noise supression from the checkbox
noiseSuppression: document.getElementById('suppressNoise').checked,
autoGainControl: false, // Optional automatic gain control
latency: 0, // Ask for minimum latency
echoCancellation: false }, // Echo cancellation unnecessary here
video: false }); // No video

// Create a MediaStreamAudioSourceNode from the audio stream
const micSourceNode = new MediaStreamAudioSourceNode(context,
Expand Down Expand Up @@ -278,6 +286,7 @@ <h3>Apple Safari users: <a
let length = event.data.recordingLength;
console.log('Seconds Recorded: ' + length / 16000);

// Convert the floating point array buffer to audio/l16 PCM
let buffer = event.data.buffer[0];
let pcmData = new Uint8Array(length * 2);
for (let index = 0; index < length; ++index) {
Expand All @@ -288,6 +297,7 @@ <h3>Apple Safari users: <a
pcmData[index * 2 + 1] = (sample >> 8) & 255; // high byte
}

// Put the raw PCM data in a blob and upload it
let formData = new FormData();
let blob = new Blob([pcmData], { type: 'audio/l16' });
formData.append('audio', blob, 'audio.raw');
Expand All @@ -301,20 +311,23 @@ <h3>Apple Safari users: <a
}).catch(error => {
alert('Upload error:' + error);
});


// Stop the recording if the buffer is full
} else if (event.data.message === 'MAX_RECORDING_LENGTH_REACHED') {
stopRecording();


// Set the duration meter
} else if (event.data.message === 'UPDATE_RECORDING_LENGTH') {
let seconds = event.data.recordingLength / 16000
document.getElementById('full').value = seconds.toFixed(2);
document.getElementById('secs').textContent =
seconds.toFixed(1).padStart(4, '0');

// Set the audio level meter
} else if (event.data.message === 'UPDATE_VISUALIZERS') {
let expKx = Math.exp(20 * event.data.gain);
document.getElementById('level').value =
((expKx - 1) / (expKx + Math.E)).toFixed(2);
let expKx = Math.exp(20 * event.data.gain); // Don't ask me;
document.getElementById('level').value = // ChatGPT-4 came
((expKx - 1) / (expKx + Math.E)).toFixed(2); // up with this.
}
}

Expand Down Expand Up @@ -352,15 +365,16 @@ <h3>Apple Safari users: <a
} catch (e) {
console.error('Error initializing recorder:', e);
console.trace(); // full stack backtrace
document.getElementById('start').disabled = true;
document.getElementById('start').disabled = true; // Disallow further interaction
document.getElementById('startOver').style.display = 'none';
alert('Error initializing recorder: ' + e + '\n\n' + Error().stack);
}
}

function startRecording() {
setNoiseSuppression();
recorder.port.postMessage({ message: 'UPDATE_RECORDING_STATE',
setRecording: true });
setRecording: true }); // Begin recording
isRecording = true;

document.getElementById('start').textContent = 'End Recording';
Expand All @@ -373,12 +387,35 @@ <h3>Apple Safari users: <a
document.getElementById('start').disabled = true;
document.getElementById('startOver').disabled = true;
recorder.port.postMessage({ message: 'UPDATE_RECORDING_STATE',
setRecording: false });
setRecording: false }); // Halt recording
isRecording = false;
}

// Setter for the noise suppression checkbox
function setNoiseSuppression() {
if (stream) {
let audioTrack = stream.getAudioTracks()[0];
if (audioTrack) {
audioTrack.applyConstraints({ noiseSuppression: document.getElementById('suppressNoise').checked })
.then(() => {
let currentSettings = audioTrack.getSettings();
if (currentSettings.noiseSuppression !== document.getElementById('suppressNoise').checked) {
console.warn('Warning: Noise suppression setting did not apply as expected.');
document.getElementById('suppressNoise').checked = currentSettings.noiseSuppression;
}
})
.catch(err => {
console.error('Failed to toggle noise suppression:', err);
document.getElementById('suppressNoise').checked = !document.getElementById('suppressNoise').checked;
});
}
}
}

</script>

<br><br>

Python Flask and JavaScript source code is
<a href="https://replit.com/@jsalsman/webrec">on Replit</a>
and <a href="https://github.com/jsalsman/webrec">GitHub.</a>
Expand Down

0 comments on commit e0cbb6e

Please sign in to comment.