Is there any way to track volume with the web audio api - javascript

I'd like to be able to track how loud the song gets in realtime, returning a number to represent the current volume of the song. The source is from a sample that plays when you click it. Ive seen tutorials on making a volume meter, but all I want is a number to measure this. here is my starting code.
const audioContext = new AudioContext();
const samplebutton = document.createElement('button')
samplebutton.innerText = 'sample'
samplebutton.addEventListener('click', async () => {
let volume = 0
const response = await fetch('testsong.wav')
const soundBuffer = await response.arrayBuffer()
const sampleBuffer = await audioContext.decodeAudioData(soundBuffer)
const sampleSource = audioContext.createBufferSource()
sampleSource.buffer = sampleBuffer
sampleSource.connect(audioContext.destination)
sampleSource.start()
function TrackVolume(){
}

You can calculate the volume by passing the audio through an AnalyserNode. With it you can get the amplitudes of every frequency at a specific moment in time and calculate the volume of the audio file.
const audioContext = new AudioContext();
const samplebutton = document.createElement('button')
samplebutton.innerText = 'sample'
samplebutton.addEventListener('click', async () => {
const response = await fetch('testsong.wav')
const soundBuffer = await response.arrayBuffer()
const sampleBuffer = await audioContext.decodeAudioData(soundBuffer)
const analyser = audioContext.createAnalyser();
const sampleSource = audioContext.createBufferSource()
sampleSource.buffer = sampleBuffer
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
sampleSource.connect(analyser);
analyser.connect(audioContext.destination)
sampleSource.start()
function caclculateVolume() {
analyser.getByteFrequencyData(dataArray)
let sum = 0;
for (const amplitude of dataArray) {
sum += amplitude * amplitude
}
const volume = Math.sqrt(sum / dataArray.length)
console.log(volume)
requestAnimationFrame(caclculateVolume)
}
caclculateVolume()
});

Related

Measure memory usage when algorithm is running

I have app witch visualize sorting alogrith i want to show user how much memory used each one of them when was runned it should be done on button click my stack is typescript and d3.js . I use Vite.js for building the app.
This is the button click code so far
let sortingInProgress = false
let timeInfo = '0.00 s'
const sortingPromise = new Promise<void>(resolve => {
START_BUTTON.addEventListener('click', async () => {
if (sortingInProgress) {
console.log('stoped')
return
}
sortingInProgress = true
START_BUTTON.disabled = true
SELECT_DATA_SIZE.disabled = true
SELECT_SORTING_ALGORITHM.disabled = true
const startTime = performance.now()
const sort = SelectAlgorithm(data, algorithmType)
await sort(updateBars)
const endTime = performance.now()
const totalTime = ((endTime - startTime) / 1000).toFixed(2) // get alogrithm running time in seconds
console.log(totalTime)
timeInfo = `${totalTime} s`
resolve()
})
})
sortingPromise.then(() => {
svg.selectAll('rect').style('fill', 'black')
sortingInProgress = false
SELECT_DATA_SIZE.disabled = false
SELECT_SORTING_ALGORITHM.disabled = false
SORT_TIME.textContent = timeInfo
})

Smoothing out voice packets using Web API

Recently I've been working on a voice platform allowing for users to talk to each other under certain conditions. However, it only seems to be smooth when your ping is really low.
Here's the structure currently:
Raw PCM Audio From User -> Web Socket -> Sent to all clients that meet a certain condition
There's nothing particularly special about my WebSocket. It's made in Java and just sends the data received directly from clients to other clients (just temporary).
Issue:
For users that have a decent amount of ping (>100ms) their audio cuts out (choppy) at certain parts and doesn't seem to load fast enough even with the code I have in place. If a video of this will help, let me know!
This is the code I have for recording and playback currently (using AudioWorkletProcessors)
Recording:
buffers = [];
buffersLength = 0;
process(inputs, _, parameters) {
const [input] = inputs;
if (parameters.muted[0] == 1) {
return true;
}
// Create one buffer from this input
const dataLen = input[0].byteLength;
const channels = input.length;
const bufferForSocket = new Uint8Array(dataLen * channels + 9);
bufferForSocket.set(new Uint8Array([channels]), 0);
bufferForSocket.set(numberToArrayBuffer(sampleRate), 1);
bufferForSocket.set(numberToArrayBuffer(input[0].byteLength), 5);
for (let i = 0; i < channels; i++) {
bufferForSocket.set(new Uint8Array(input[i].buffer), 9 + dataLen * i);
}
// Add buffers to a list
this.buffers.push(bufferForSocket);
this.buffersLength += bufferForSocket.byteLength;
// If we have 25 buffers, send them off to websocket
if (this.buffers.length >= 25) {
const combinedBuffer = new Uint8Array(
this.buffersLength + 4 + 4 * this.buffers.length
);
combinedBuffer.set(numberToArrayBuffer(this.buffers.length), 0);
let offset = 4;
for (let i = 0; i < this.buffers.length; i++) {
const buffer = this.buffers[i];
combinedBuffer.set(numberToArrayBuffer(buffer.byteLength), offset);
combinedBuffer.set(buffer, offset + 4);
offset += buffer.byteLength + 4;
}
this.buffers.length = 0;
this.buffersLength = 0;
// This is what sends to WebSocket
this.port.postMessage(combinedBuffer.buffer);
}
return true;
}
Playback:
class extends AudioWorkletProcessor {
buffers = new LinkedList();
timeTillNextBuffer = 0;
process(_, outputs, __) {
const [output] = outputs;
const linkedBuffers = this.buffers.last();
// If we aren't currently playing a buffer and we cannot play a buffer right now, return
if (
linkedBuffers == null ||
(linkedBuffers.buffers.length === 0 && this.timeTillNextBuffer > Date.now())
)
return true;
const buffer = linkedBuffers.buffers.removeLast();
// Current buffer is finished, remove it
if (linkedBuffers.index === linkedBuffers.buffers.length) {
this.buffers.removeLast();
}
if (buffer === null) {
return true;
}
const inputData = buffer.channels;
// put audio to output
for (let channel = 0; channel < outputs.length; channel++) {
const channelData = inputData[channel];
const outputData = output[channel];
for (let i = 0; i < channelData.length; i++) {
outputData[i] = channelData[i];
}
}
return true;
}
static get parameterDescriptors() {
return [];
}
onBuffer(buffer) {
// buffer is ArrayBuffer
const buffersGiven = new DataView(buffer, 0, 4).getUint32(0, true);
let offset = 4;
const buffers = new LinkedList();
const linkedBuffers = { index: 0, buffers };
// Read buffers from WebSocket (created in the snippet above)
for (let i = 0; i < buffersGiven; i++) {
const bufferLength = new DataView(buffer, offset, 4).getUint32(0, true);
const numberOfChannels = new DataView(buffer, offset + 4, 1).getUint8(0, true);
const sampleRate = new DataView(buffer, offset + 5, 4).getUint32(0, true);
const channelLength = new DataView(buffer, offset + 9, 4).getUint32(0, true);
const channels = [];
for (let i = 0; i < numberOfChannels; i++) {
const start = offset + 13 + i * channelLength;
channels[i] = new Float32Array(buffer.slice(start), 0, channelLength / 4);
}
buffers.push({ channelLength, numberOfChannels, sampleRate, channels });
offset += bufferLength + 4;
}
this.buffers.push(linkedBuffers);
// Jitter buffer
this.timeTillNextBuffer = 50 - this.buffers.length * 25 + Date.now();
}
constructor() {
super();
this.port.onmessage = (e) => this.onBuffer(e.data); // Data directly from WebSocket
}
}
I heard the use of Atomics can help because of how the AudioContext plays blank audio when returning. Any tips would be greatly appreciated! Also, if anything is unclear, please let me know!
My code has somewhat of a Jitter buffer system and it doesn't seem to work at all. The audio that a user receives from me (low ping) is clear. However, they (high ping) send me choppy audio. Furthermore, this choppy audio seems to build up and it gets more delayed the more packets I receive.

Deleting old data in Realtime database using cloud functions

I have been struggling for a very long time to achieve deleting old data in the realtime database using cloud functions. What am I doing wrong?
I want to delete data that's older than 2 hours every 60 minutes.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
'use strict';
const CUT_OFF_TIME = 2 * 60 * 60 * 1000; // 2 Hours in milliseconds.
exports.deleteOldItems = functions.pubsub.schedule('every 60 minutes').onRun(async context => {
admin.database().ref('/').once('value', async (data) => {
var ref = data.val();
const now = Date.now();
const cutoff = now - CUT_OFF_TIME;
const oldItemsQuery = ref.orderByChild('timestamp').endAt(cutoff);
const snapshot = await oldItemsQuery.once('value');
// create a map with all children that need to be removed
const updates = {};
snapshot.forEach(child => {
updates[child.key] = null;
});
return ref.update(updates);
});
});
I didn't check your code for the query based on the cutoff, but we can already see that
var ref = data.val();
//...
const oldItemsQuery = ref.orderByChild('timestamp').endAt(cutoff);
//...
return ref.update(updates);
cannot work because data.val() is not a Reference.
You should adapt your code as follows (untested):
exports.deleteOldItems = functions.pubsub.schedule('every 60 minutes').onRun(async (context) => {
const ref = admin.database().ref();
const now = Date.now();
const cutoff = now - CUT_OFF_TIME;
const oldItemsQuery = ref.orderByChild('timestamp').endAt(cutoff);
const snapshot = await oldItemsQuery.get();
// create a map with all children that need to be removed
const updates = {};
snapshot.forEach(child => {
updates[child.key] = null;
});
return ref.update(updates);
});

Determine if there is a pause in speech using Web Audio API AudioContext

Trying to understand the Web Audio API better. We're using it to create an AudioContext and then sending audio to be transcribed. I want to be able to determine when there is a natural pause in speech or when the user stopped speaking.
Is there some data in onaudioprocess callback that can be accessed to determine pauses/breaks in speech?
let context = new AudioContext();
context.onstatechange = () => {};
this.setState({ context: context });
let source = context.createMediaStreamSource(stream);
let processor = context.createScriptProcessor(4096, 1, 1);
source.connect(processor);
processor.connect(context.destination);
processor.onaudioprocess = (event) => {
// Do some magic here
}
I tried a solution that is suggested on this post but did not achieve the results I need. Post: HTML Audio recording until silence?
When I parse for silence as the post suggests, I get the same result - either 0 or 128
let context = new AudioContext();
let source = context.createMediaStreamSource(stream);
let processor = context.createScriptProcessor(4096, 1, 1);
source.connect(processor);
processor.connect(context.destination);
/***
* Crete analyser
*
**/
let analyser = context.createAnalyser();
analyser.smoothingTimeConstant = 0;
analyser.fftSize = 2048;
let buffLength = analyser.frequencyBinCount;
let arrayFreqDomain = new Uint8Array(buffLength);
let arrayTimeDomain = new Uint8Array(buffLength);
processor.connect(analyser);
processor.onaudioprocess = (event) => {
/**
*
* Parse live real-time buffer looking for silence
*
**/
let f, t;
analyser.getByteFrequencyData(arrayFreqDomain);
analyser.getByteTimeDomainData(arrayTimeDomain);
for (var i = 0; i < buffLength; i++) {
arrayFreqDomain[i]; <---- gives 0 value always
arrayTimeDomain[i]; <---- gives 128 value always
}
}
Looking at the documentation for the getByteFrequencyData method I can see how it is supposed to be giving a different value (in the documentation example it will give a different barHeight), but it isn't working for me. https://developer.mozilla.org/en-US/docs/Web/API/AnalyserNode/getByteFrequencyData#Example

Is there a way to release OfflineAudioContext memory allocation?

Now I'm developing a software from Electron. It is a music player application.
What I would to do is I have to extract audio feature from (an) incoming song(s). This is not realtime extraction because I would like to extract feature entire of a song.
I use a library call Meyda and Web Audio API. I have noticed that my implementation consume amount of RAM (about ~2,000 MB).
Here is my implementation:
let offlineCtx = new OfflineAudioContext(
2,
duration * sampleRate,
sampleRate
)
let source = offlineCtx.createBufferSource()
let buffer = await audioCtx.decodeAudioData(songData.buffer)
source.buffer = buffer
source.connect(offlineCtx.destination)
source.start()
const SLICING_WINDOW_SIZE = 1024
let renderedBuffer = await offlineCtx.startRendering()
let channelData = await renderedBuffer.getChannelData(0)
let results = []
for (let i = 0; i < channelData.length - SLICING_WINDOW_SIZE; i += SLICING_WINDOW_SIZE) {
const r = Meyda.extract(
'mfcc',
channelData.slice(i, i + SLICING_WINDOW_SIZE)
)
results.push(r)
}
Is there a way to reduce RAM consuming? Thanks!

Categories

Resources