### Installing Node.js Dependencies (npm) Source: https://github.com/mtg/essentia.js/blob/master/examples/starter-code/nodejs-basic-examples/README.md Installs project dependencies listed in package.json, specifically saving them as development dependencies required for building or testing the project. ```Shell npm install --save-dev ``` -------------------------------- ### Installing essentia.js via NPM Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/1. Getting started.md Installs the essentia.js library using the npm package manager. ```bash npm install essentia.js ``` -------------------------------- ### Running Essentia.js Algorithms Example Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/1. Getting started.md Provides a comprehensive example of using the instantiated Essentia object to perform audio analysis. Includes loading audio from a URL, converting data types, running 'ReplayGain' and 'PitchYinProbabilistic' algorithms, accessing results, and cleaning up resources. ```javascript const audioCtx = new AudioContext(); let audioURL = "https://freesound.org/data/previews/328/328857_230356-lq.mp3"; // decode audio data const audioBuffer = await essentia.getAudioBufferFromURL(audioURL, audioCtx); /* OR * you could also decode audio from any other * source and pass to an essentia algorithm. */ // convert the JS float32 typed array into std::vector const inputSignalVector = essentia.arrayToVector(audioBuffer.getChannelData(0)); // Computing ReplayGain from an input audio signal vector // The algorithm return float type // check https://essentia.upf.edu/reference/std_ReplayGain.html let outputRG = essentia.ReplayGain(inputSignalVector, // input 44100); // sampleRate (parameter optional) console.log(outputRG.replayGain); // Running PitchYinProbabilistic algorithm on an input audio signal vector // check https://essentia.upf.edu/reference/std_PitchYinProbabilistic.html let outputPyYin = essentia.PitchYinProbabilistic(inputSignalVector, // input // parameters (optional) 4096, // frameSize 256, // hopSize 0.1, // lowRMSThreshold 'zero', // outputUnvoiced, false, // preciseTime 44100); //sampleRate let pitches = essentia.vectorToArray(outputPyYin.pitch); let voicedProbabilities = essentia.vectorToArray(outputPyYin.voicedProbabilities); console.log(pitch); console.log(voicedProbabilities); outputPyYin.pitch.delete() outputPyYin.voicedProbabilities.delete() // CAUTION: only use the `shutdown` and `delete` methods below if you've finished your analysis and don't plan on re-using Essentia again in your program lifecycle. // call internal essentia::shutdown C++ method essentia.shutdown(); // delete EssentiaJS instance, free JS memory essentia.delete(); ``` -------------------------------- ### Installing essentia.js via Yarn Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/1. Getting started.md Installs the essentia.js library using the Yarn package manager. ```bash yarn add essentia.js ``` -------------------------------- ### Using essentia.js with Require (NPM) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/1. Getting started.md Demonstrates how to import and instantiate the Essentia object using the require syntax common in Node.js or older module systems after installing via NPM. Shows accessing version and algorithm names. ```javascript let esPkg = require('essentia.js'); const essentia = new esPkg.Essentia(esPkg.EssentiaWASM); // prints version of the essentia wasm backend console.log(essentia.version) // prints all the available algorithm methods in Essentia console.log(essentia.algorithmNames) ``` -------------------------------- ### Running a Node.js Script Source: https://github.com/mtg/essentia.js/blob/master/examples/starter-code/nodejs-basic-examples/README.md Executes a specified JavaScript file using the Node.js runtime environment. Replace ` ``` -------------------------------- ### Loading essentia.js via CDN Script Tags Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/1. Getting started.md Includes the essentia.js library and its WebAssembly backend in an HTML page using script tags pointing to CDN URLs. Replace with the desired library version. ```html ``` -------------------------------- ### Instantiating Essentia with Local ES6 Imports Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/1. Getting started.md Shows how to import Essentia core and WASM modules using relative paths (assuming local files) and instantiate the main Essentia object. This sets up the object needed to run algorithms. ```javascript import Essentia from './essentia.js-core.es.js'; // import essentia-wasm-module import { EssentiaWASM } from './essentia-wasm.es.js'; // create essentia object with all the methods to run various algorithms // by loading the wasm back-end. // here, `EssentiaModule` is an emscripten module object imported to the global namespace let essentia = new Essentia(EssentiaWASM); ``` -------------------------------- ### Importing essentia.js via CDN (ES6) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/1. Getting started.md Imports the Essentia core and WASM module using ES6 syntax directly from CDN URLs. Demonstrates instantiating the Essentia object and accessing version and algorithm names. Note the recommendation to use WASM in workers. ```javascript import Essentia from 'https://cdn.jsdelivr.net/npm/essentia.js@/dist/essentia.js-core.es.js'; // import essentia-wasm-module import { EssentiaWASM } from 'https://cdn.jsdelivr.net/npm/essentia.js@/dist/essentia-wasm.es.js'; const essentia = new Essentia(EssentiaWASM); // prints version of essentia wasm backend console.log(essentia.version) // prints all the available algorithm methods in Essentia console.log(essentia.algorithmNames) ``` -------------------------------- ### Run Local Development Server and Client (Shell) Source: https://github.com/mtg/essentia.js/blob/master/examples/demos/discogs-autotagging/README.md Navigate to the server and views directories and start the development servers using npm. This setup is suitable for local development and testing. ```Shell cd server npm run dev cd ../views npm run dev ``` -------------------------------- ### Processing Audio Frames with Essentia.js Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/1. Getting started.md This JavaScript snippet demonstrates how to generate overlapping frames from audio data using essentia.js's FrameGenerator and iterate through them to apply algorithms like Windowing for frame-wise processing. ```JavaScript // generate overlapping frames of audio signal from given parameters const frames = essentia.FrameGenerator(audioData, 1024, // frameSize 512); // hopSize // Iterate through every frame and do the desired audio processing // In this case, we just apply a hanning window to the signal for (var i=0; i { gumStream = stream; if (gumStream.active) { mic = audioCtx.createMediaStreamSource(stream); if (audioCtx.state == "suspended") { audioCtx.resume(); } scriptNode = audioCtx.createScriptProcessor(bufferSize, 1, 1); // onprocess callback (where we perform our analysis with essentia.js) scriptNode.onaudioprocess = essentiaExtractorCallback; mic.connect(scriptNode); scriptNode.connect(audioCtx.destination); btnCallback(); // restore button state } else { throw "Mic stream not active"; } } ).catch((message) => { throw "Could not access microphone - " + message; }); } else { throw "Could not access microphone - getUserMedia not available"; } } ``` -------------------------------- ### Handling Button Click to Start/Stop Recording (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Sets up a click event handler for the record button. This handler checks the current state (recording or not), and is intended to trigger the loading of the essentia.js backend, instantiation of the core API, and then call `startMicRecordStream` or `stopMicRecordStream` accordingly (though the provided snippet is incomplete, only showing the start of the handler). ```javascript window.onload = () => { recordButton.onclick = function() { var recording = this.classList.contains("recording"); ``` -------------------------------- ### Start/Stop Recording Logic (ScriptProcessorNode) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Implements the logic for starting or stopping microphone recording within an event handler. It checks the recording state, disables the button, initializes Essentia.js if it's the first run, and calls helper functions to manage the audio stream. ```JavaScript if (!recording) { this.setAttribute("disabled", true); EssentiaWASM().then(function(essentiaModule) { if (!isEssentiaInstance) { essentia = new Essentia(essentiaModule); isEssentiaInstance = true; } startMicRecordStream(enableButton); // `enableButton` is just a function that re-enables the Start/Stop button }); } else { stopMicRecordStream(); } }; ``` -------------------------------- ### Feature Extraction Worker Setup and Processing (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md Sets up a Web Worker for feature extraction. It imports necessary scripts, initializes the EssentiaTFInputExtractor, and defines an onmessage handler to receive audio data, compute frame-wise features (log-scaled melbands), and post the results back to the main thread. ```JavaScript // extractor-worker.js importScripts("./lib/essentia-wasm.umd.js"); importScripts("./lib/essentia.js-model.umd.js"); const EssentiaWASM = Module; // name of WASM module before ES6 export const extractor = new EssentiaModel.EssentiaTFInputExtractor(EssentiaWASM, "musicnn"); self.onmessage = e => { let features = extractor.computeFrameWise(e.data, 256); // post the feature as message to the main thread self.postMessage(features); } ``` -------------------------------- ### Building Custom Essentia C++ Extractor (Bash) Source: https://github.com/mtg/essentia.js/blob/master/src/cpp/custom/README.md Command to build the custom C++ Essentia extractor using the provided Makefile. This step requires having the necessary dependencies installed for building Essentia WASM. ```bash make ``` -------------------------------- ### Inference Worker Setup and Prediction (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md Sets up a Web Worker for model inference. It imports Tensorflow.js and the essentia.js model add-on, initializes a TensorflowMusiCNN model from a specified URL, and defines an onmessage handler to receive features, perform prediction using the loaded model, and post the predictions back to the main thread. ```JavaScript // inference-worker.js importScripts("https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"); importScripts("./lib/essentia.js-model.umd.js"); const modelURL = "models/msd-musicnn-1/model.json" const musiCNN = new EssentiaModel.TensorflowMusiCNN(tf, modelURL); let modelIsLoaded = false; // initialize() will load the model from the given URL onto memory musiCNN.initialize().then(() => modelIsLoaded = true ); console.log(`Using TF ${tf.getBackend()} backend`); self.onmessage = e => { if (modelIsLoaded) { musiCNN.predict(e.data, true) .then((predictions) => self.postMessage(predictions)); // send the predictions to the main thread } } ``` -------------------------------- ### Setup MessageChannel and Transfer Port (inference-worker.js) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md This JavaScript code snippet from inference-worker.js shows how to establish a MessageChannel for bidirectional communication. It sends one of the MessagePort's (channel.port2) to the main thread for transfer to the AudioWorklet, while retaining the other port (channel.port1) to receive feature data from the AudioWorklet for subsequent model prediction. ```javascript // inference-worker.js const channel = new MessageChannel(); // bidirectional comm channel const port1 = channel.port1; // send port2 to main thread, where it will be transferred to the AudioWorklet so it can use it for sending features postMessage({ port: channel.port2 }, [channel.port2]); // sending as array on 2nd argument transfers ownership of the object, so it cannot be used inside `inference-worker.js` anymore. // port1 will be used to receive features from AudioWorklet port1.onmessage = function listenToAudioWorklet(msg) { if (msg.data.features) { model.predict(msg.data.features).then((activations) => { self.postMessage({ activations: activations }); }); } } ``` -------------------------------- ### Display Essentia Bindings Configuration Help (Bash) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/4. Building from source.md Shows the available command-line options and usage instructions for the `configure_bindings.py` script. ```Bash python configure_bindings.py -h ``` -------------------------------- ### Basic Essentia.js Model Loading and Analysis (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md Initializes the AudioContext, defines model and audio URLs, creates EssentiaModel instances, loads the Essentia WASM backend, fetches and decodes an audio file from a URL, and performs audio analysis and model prediction on the main thread upon page load. ```javascript // init audio context: we will need it to decode our audio file const audioCtx = new (AudioContext || new webkitAudioContext())(); // model variables const modelURL = "./msd-musicnn-1/model.json"; let extractor = null; let musicnn = new EssentiaModel.TensorflowMusiCNN(tf, modelURL, true); // get audio track URL const audioURL = "https://freesound.org/data/previews/277/277325_4548252-lq.mp3"; window.onload = () => { // load Essentia WASM backend EssentiaWASM().then(wasmModule => { extractor = new EssentiaModel.EssentiaTFInputExtractor(wasmModule, "musicnn", false); // fetch audio and decode, then analyse extractor.getAudioBufferFromURL(audioURL, audioCtx).then(analyse); }); }; // analyse on click async function analyse(buffer) { const audioData = await extractor.downsampleAudioBuffer(buffer); const features = await extractor.computeFrameWise(audioData, 256); await musicnn.initialize(); const predictions = await musicnn.predict(features, true); // creates a new div to display the predictions and appends to DOM showResults(predictions); } ``` -------------------------------- ### Build and Run Docker Image for Deployment (Shell) Source: https://github.com/mtg/essentia.js/blob/master/examples/demos/discogs-autotagging/README.md Build a Docker image tagged 'discogs-demo:latest' from the current directory's Dockerfile, then run the image, removing the container on exit and mapping host port 8000 to container port 8000. ```Shell docker build -t discogs-demo:latest . docker run --rm -it -p 8000:8000 discogs-demo:latest node server.js ``` -------------------------------- ### Initializing Global Variables for Essentia.js and Web Audio API (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Defines global JavaScript variables required for integrating essentia.js with the Web Audio API using ScriptProcessorNode. Includes variables for the essentia instance, audio context, buffer size, microphone stream, script node, and references to HTML elements for UI interaction and displaying results. ```javascript // global var to load essentia instance from wasm build let essentia; let isEssentiaInstance = false; // global audio vars let audioCtx; let bufferSize = 1024; // buffer size for mic stream and ScriptProcessorNode let mic = null; let scriptNode = null; let gumStream; const AudioContext = window.AudioContext || window.webkitAudioContext; audioCtx = new AudioContext(); let plotDiv = document.querySelector('#plotDiv'); // html div to print our results to let recordButton = document.querySelector('#recordButton'); ``` -------------------------------- ### Instantiating Essentia in AudioWorklet (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Shows how to instantiate the Essentia object within the AudioWorklet processor code after the bundled code has been loaded. It passes EssentiaWASM to the constructor, which is expected to be available in the worklet scope after loading the essentia.js library. Requires essentia.js library to be loaded. ```javascript // essentia-worklet-processor.js let essentia = new Essentia(EssentiaWASM); ``` -------------------------------- ### Configure Essentia Bindings with Algorithm List (Bash) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/4. Building from source.md Specifies the list of algorithms to include when configuring Essentia.js bindings by providing a text file containing algorithm names, one per line. ```Bash python configure_bindings.py -i your_included_algos_list.txt ``` -------------------------------- ### Fetching and Preprocessing Audio (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md Defines a function for a button click handler that fetches audio from a URL, decodes it into an AudioBuffer, downsamples it to a specified sample rate, and then sends the resulting audio signal to the feature extraction worker. ```JavaScript // main.js const audioSampleRate = 16000; function onClickAction() { extractor.getAudioBufferFromURL(audioURL, audioCtx) .then((audioBuffer) => extractor.downsampleAudioBuffer(audioBuffer, audioSampleRate) ) // finally we send our preprocessed signal to the feature extraction worker .then((audioSignal) => extractorWorker.postMessage(audioSignal) ); } ``` -------------------------------- ### Loading Essentia.js Libraries (HTML) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md Includes the necessary script tags in the HTML document to load the essentia.js WASM backend and the essentia.js model add-on libraries. ```HTML ``` -------------------------------- ### Build Custom Essentia C++ Extractor (Bash) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/4. Building from source.md Executes the Makefile to build the custom C++ Essentia extractor, cross-compiling it to WebAssembly using the configured toolchain. ```Bash make ``` -------------------------------- ### Importing Essentia.js and Dependencies via Script Tags (HTML) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md Includes the necessary JavaScript libraries (Essentia.js WASM backend, Essentia.js model utilities, and TensorFlow.js) using script tags in an HTML file. This makes the libraries available globally for use in the main script. ```html ``` -------------------------------- ### Creating Essentia AudioWorkletNode (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Defines an asynchronous function to create an AudioWorkletNode for essentia.js. It uses URLFromFiles to fetch and concatenate necessary JavaScript files (essentia.js UMD, essentia.js-core ES, and the custom processor code) into a single blob URL, then adds this bundled code as an AudioWorklet module. Finally, it instantiates and returns the AudioWorkletNode. Requires URLFromFiles utility. ```javascript // main.js const workletProcessorCode = ["https://cdn.jsdelivr.net/npm/essentia.js@/dist/essentia-wasm.umd.js", "https://cdn.jsdelivr.net/npm/essentia.js@/dist/essentia.js-core.es.js", "essentia-worklet-processor.js"]; export async function createEssentiaNode (audioCtx) { try { let concatenatedCode = await URLFromFiles(workletProcessorCode) await audioCtx.audioWorklet.addModule(concatenatedCode); // add our custom code to the worklet scope } catch(e) { console.log(e); } return new AudioWorkletNode(audioCtx, 'essentia-worklet-processor'); } ``` -------------------------------- ### Essentia AudioWorkletProcessor Class (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Defines the custom AudioWorkletProcessor class ('EssentiaWorkletProcessor') that runs in the audio rendering thread. It initializes Essentia.js, implements the `process` method to handle incoming audio frames, converts the input to a format usable by Essentia, performs an analysis (like RMS), and outputs the result. ```JavaScript // essentia-worklet-processor.js import { EssentiaWASM } from "https://cdn.jsdelivr.net/npm/essentia.js@/dist/essentia-wasm.es.js"; import Essentia from "https://cdn.jsdelivr.net/npm/essentia.js@/dist/essentia.js-core.es.js"; let essentia = new Essentia(EssentiaWASM); class EssentiaWorkletProcessor extends AudioWorkletProcessor { constructor() { super(); this.essentia = essentia; console.log('Backend - essentia:' + this.essentia.version + '- http://essentia.upf.edu'); } //System-invoked process callback function. process(inputs, outputs, parameters) { // and will have as many as were specified in the options passed to the AudioWorkletNode constructor, each subsequently spanning potentially multiple channels let input = inputs[0]; let output = outputs[0]; // convert the input audio frame array from channel 0 to a std::vector type for using it in essentia let vectorInput = this.essentia.arrayToVector(input[0]); // In this case we compute the Root Mean Square of every input audio frame // check https://mtg.github.io/essentia.js/docs/api/Essentia.html#RMS let rmsFrame = this.essentia.RMS(vectorInput) // input audio frame output[0][0] = rmsFrame.rms; return true; // keep the process running } } registerProcessor('essentia-worklet-processor', EssentiaWorkletProcessor); // must use the same name we gave our processor in `createEssentiaNode` ``` -------------------------------- ### Create Inference Worker and Handle Port Transfer (main.js) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md This JavaScript code snippet from main.js demonstrates how to create a new Web Worker for inference, set up a message listener to receive a MessagePort transferred from the worker, and then use that port to initiate the audio processing pipeline. It also shows how to listen for model predictions from the worker. ```javascript // main.js function createInferenceWorker() { // `inferenceWorker` and `workerToWorkletPort` are globals inferenceWorker = new Worker('./scripts/inference-worker.js'); inferenceWorker.onmessage = function listenToWorker(msg) { if (msg.data.port) { // listen out for port transfer workerToWorkletPort = msg.data.port; console.log("Received port from worker\n", workerToWorkletPort); // `start()` gets mic stream from `getUserMedia`, creates feature extraction AudioWorklet node, sends it the `workerToWorkletPort`, and connects audio graph start(); } else if (msg.data.predictions) { // listen out for model output printActivations(msg.data.predictions); } }; } ``` -------------------------------- ### Using Custom Essentia WASM Extractor in JavaScript Source: https://github.com/mtg/essentia.js/blob/master/src/cpp/custom/README.md Demonstrates how to import, instantiate, configure, compute with, reset, and clean up a custom Essentia WASM extractor (LogMelSpectrogramExtractor) in JavaScript. Includes fetching and processing audio data using the Web Audio API. ```JavaScript // import essentia-wasm backend import { EssentiaWASM } from 'essentia-custom-extractor.module.js'; // create a instance of our custom 'LogMelSpectrogramExtractor' // by passing our configuration settings for the given parameters const extractor = new EssentiaWASM.LogMelSpectrogramExtractor(1024, // frameSize 512, // hopSize 96, // numBands 'hann'); // windowType // Use the Web Audio API to decode the audio channel data from an url of a audio file const audioURL = "https://freesound.org/data/previews/328/328857_230356-lq.mp3"; const audioContext = new AudioContext(); const response = await fetch(audioURL); const arrayBuffer = await response.arrayBuffer(); const audioBuffer = await audioContext.decodeAudioData(arrayBuffer); // getChannelData of channel number 0 (since it's a mono audio signal) const audioData = audioBuffer.getChannelData(0); // Now, let's compute the log-mel spectrogram feature for the given audio input let melSpectrogram = extractor.compute(audioData); // reset the internal states of the algorithms used in the extractor extractor.reset(); // reconfigure our extractor with new parmeter settings extractor.configure(1024, 512, 128, 'hann'); // compute with new settings let melSpectrogram = extractor.compute(audioData); // delete algorithms and free memory after it's use extractor.shutdown(); extractor.delete(); ``` -------------------------------- ### Initializing EssentiaTFInputExtractor (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md Initializes the EssentiaTFInputExtractor instance on the main thread after the WASM module is loaded. This extractor is configured for use with 'musicnn' models. ```JavaScript // main.js let extractor; EssentiaWASM().then((wasmModule) => { extractor = new EssentiaModel.EssentiaTFInputExtractor(wasmModule, "musicnn"); }) ``` -------------------------------- ### Connect AudioWorkletNode in Graph (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Illustrates how to integrate the Essentia AudioWorkletNode into the Web Audio API graph. It shows connecting the microphone source node (`micNode`) to the `essentiaNode`, ensuring the `essentiaNode` is created only once before connecting. ```JavaScript micNode = audioContext.createMediaStreamSource(gumStream); // ... // create essentia node only once (avoid registering processor repeatedly) if (!essentiaNode) { essentiaNode = await createEssentiaNode(audioContext); } micNode.connect(essentiaNode); ``` -------------------------------- ### Use Custom Essentia WASM Extractor (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/4. Building from source.md Demonstrates how to import, instantiate, configure, compute with, reset, and clean up a custom Essentia WASM extractor (`LogMelSpectrogramExtractor`) in JavaScript. It includes fetching and decoding audio data using the Web Audio API for input. ```JavaScript // import essentia-wasm backend import { EssentiaWASM } from 'essentia-custom-extractor.module.js'; // create an instance of our custom 'LogMelSpectrogramExtractor' // by passing our configuration settings for the given parameters const extractor = new EssentiaWASM.LogMelSpectrogramExtractor(1024, // frameSize 512, // hopSize 96, // numBands 'hann'); // windowType // Use the Web Audio API to decode the audio channel data from an url of a audio file const audioURL = "https://freesound.org/data/previews/328/328857_230356-lq.mp3"; const audioContext = new AudioContext(); const response = await fetch(audioURL); const arrayBuffer = await response.arrayBuffer(); const audioBuffer = await audioContext.decodeAudioData(arrayBuffer); // getChannelData of channel number 0 (since it's a mono audio signal) const audioData = audioBuffer.getChannelData(0); // Now, let's compute the log-mel spectrogram feature for the given audio input let melSpectrogram = extractor.compute(audioData); // reset the internal states of the algorithms used in the extractor extractor.reset(); // reconfigure our extractor with new parmeter settings extractor.configure(1024, 512, 128, 'hann'); // compute with new settings let melSpectrogram = extractor.compute(audioData); // delete algorithms and free memory after it's use extractor.shutdown(); extractor.delete(); ``` -------------------------------- ### Processing Audio with Essentia.js RMS Algorithm (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Defines the `essentiaExtractorCallback` function, which is triggered by the ScriptProcessorNode's `audioprocess` event. It converts the input audio buffer to an Essentia-compatible vector, applies the RMS algorithm, extracts the result, and displays it in a UI element. ```javascript // ScriptNodeProcessor callback function to calculate RMS using essentia.js function essentiaExtractorCallback(audioProcessingEvent) { // convert the float32 audio data into std::vector for using with essentia algos var vectorSignal = essentia.arrayToVector( audioProcessingEvent.inputBuffer.getChannelData(0) ); if (!vectorSignal) { throw "onRecordingError: empty audio signal input found!"; } // check https://mtg.github.io/essentia.js/docs/api/Essentia.html#RMS let algoOutput = essentia.RMS(vectorSignal); // convert the output to js arrray let rmsValue = algoOutput.rms; plotDiv.innerText = rmsValue; } ``` -------------------------------- ### Spawning Web Workers for Deferred Processing (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md Demonstrates how to create new Web Worker instances for offloading computationally intensive tasks like feature extraction and model inference to separate threads, preventing the main UI thread from blocking. ```javascript // main.js const extractorWorker = new Worker("extractor-worker.js"); const inferenceWorker = new Worker("inference-worker.js"); ``` -------------------------------- ### Create Essentia AudioWorkletNode (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Defines an asynchronous function to create and return an AudioWorkletNode configured for Essentia.js processing. It first adds the custom processor module file ('essentia-worklet-processor.js') to the AudioWorklet scope and then instantiates the node using the registered processor name. ```JavaScript // main.js const workletProcessorCode = "essentia-worklet-processor.js"; export async function createEssentiaNode (audioCtx) { try { await audioCtx.audioWorklet.addModule(workletProcessorCode); // add our custom code to the worklet scope and register our processor as `essentia-worklet-processor` } catch(e) { console.log(e); } return new AudioWorkletNode(audioCtx, 'essentia-worklet-processor'); // instantiate our custom processor as an AudioWorkletNode } ``` -------------------------------- ### Implementing Audio Frame Buffering and Feature Extraction in Essentia.js AudioWorklet - JavaScript Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md This JavaScript snippet shows the implementation of an `AudioWorkletProcessor` that handles incoming audio frames from the Web Audio API. It uses `RingBuffer` instances to accumulate samples to the required frame and hop sizes for Essentia.js feature extraction, computes mel spectrum features, and manages a patch of features before sending it to a worker for inference. ```javascript // feature-extract-processor.js import { EssentiaWASM } from "../lib/essentia-wasm.es.js"; import { EssentiaTensorflowInputExtractor} from "../lib/essentia.js-model.es.js"; import { RingBuffer } from "../lib/wasm-audio-helper.js"; // ... class FeatureExtractProcessor extends AudioWorkletProcessor { constructor() { super(); this._frameSize = 512; this._hopSize = 256; this._channelCount = 1; this._patchHop = new PatchHop(187, 1/3); // if patchSize at 16kHz and 256 hopSize corresponds to about 3s of audio, this would jump by 1s this._extractor = new EssentiaTFInputExtractor(EssentiaWASM, 'musicnn'); this._features = { melSpectrum: getZeroMatrix(187, 96), // init melSpectrum 187x96 matrix with zeros batchSize: 187, melBandsSize: 96, patchSize: 187 }; // buffer size mismatch helpers this._hopRingBuffer = new RingBuffer(this._hopSize, this._channelCount); this._frameRingBuffer = new RingBuffer(this._frameSize, this._channelCount); this._hopData = [new Float32Array(this._hopSize)]; this._frameData = [new Float32Array(this._frameSize)]; // array of arrays because RingBuffer expects potentially multichannel inputs; in our case there's only one channel // zero-pad `hopData` so we have 512 values in `frameData` upon the first 256 samples we get in this._hopData[0].fill(0); // setup worker comms // ... } process(inputList) { let input = inputList[0]; this._hopRingBuffer.push(input); if (this._hopRingBuffer.framesAvailable >= this._hopSize) { // always push the previous hopData samples to create overlap of hopSize this._frameRingBuffer.push(this._hopData); // RingBuffer's pull method places data from its internal memory onto its only argument (this._hopData in this case) this._hopRingBuffer.pull(this._hopData); this._frameRingBuffer.push(this._hopData); // push new hopData samples if (this._frameRingBuffer.framesAvailable >= this._frameSize) { // here 512 samples are "pulled" from inside the ring buffer and placed on `this._frameData` this._frameRingBuffer.pull(this._frameData); this._features.melSpectrum.push(this._extractor.compute(this._frameData[0]).melSpectrum); // push new frame of melbands onto the end this._features.melSpectrum.shift(); // pop the first (oldest) frame of melbands to keep the patch size constant this._patchHop.incrementFrame(); if (this._patchHop.readyToHop() && this._workerPort) { // send features to Worker for inference this._workerPort.postMessage({ features: this._features }); } } } return true; // keep the processor running } } ``` -------------------------------- ### Receive MessagePort in AudioWorkletProcessor (feature-extract-processor.js) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md This JavaScript code snippet from an AudioWorkletProcessor demonstrates how to receive a MessagePort from the main thread via the processor's own port. This received port (_workerPort) is intended for sending processed feature data back to the inference worker, enabling communication between the AudioWorklet and the Worker thread. ```javascript // feature-extract-processor.js class FeatureExtractProcessor extends AudioWorkletProcessor { constructor() { // ... // setup worker comms this._workerPort = undefined; this._workerPortAvailable = false; this.port.onmessage = (msg) => { if (msg.data.port) { console.info('Worklet received port from main thread\n', msg.data.port); this._workerPort = msg.data.port; this._workerPortAvailable = true; } }; } process() { // ... } } ``` -------------------------------- ### Stopping Microphone Stream and Disconnecting Audio Nodes (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/2. Real-time analysis.md Defines the `stopMicRecordStream` function to gracefully stop the live audio input. It suspends the audio context, stops the microphone tracks, updates the UI button state, disconnects the `MediaStreamSource` and `ScriptProcessorNode` to free resources, and clears the results display. ```javascript function stopMicRecordStream() { audioCtx.suspend().then(() => { // stop mic stream gumStream.getAudioTracks().forEach(function(track) { track.stop(); }); recordButton.classList.remove("recording"); recordButton.innerHTML = 'Mic   '; mic.disconnect(); scriptNode.disconnect(); plotDiv.innerText = ""; }); } ``` -------------------------------- ### Controlling Feature Patch Sending Frequency with PatchHop in Essentia.js AudioWorklet - JavaScript Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md This JavaScript snippet defines the `PatchHop` class used in the `FeatureExtractProcessor`. It's a utility class designed to control when a patch of features is considered 'ready' to be sent for inference. It increments a frame counter and signals readiness when the counter reaches a specific fraction of the total patch size, enabling a smoother, more frequent output stream. ```javascript // feature-extract-processor.js class PatchHop { constructor(patchSize, ratio) { this.size = Math.floor(patchSize * ratio); // fraction of the total patchSize this.frameCount = 0; } incrementFrame() { this.frameCount++; this.frameCount %= this.size; } readyToHop() { if (this.frameCount === 0) { return true; } else { return false; } } } ``` -------------------------------- ### Handling Features from Extractor Worker (JavaScript) Source: https://github.com/mtg/essentia.js/blob/master/docs/tutorials/3. Machine learning inference with Essentia.js.md Defines the onmessage handler on the main thread for receiving computed features from the feature extraction worker. It then forwards these features to the inference worker for model prediction. ```JavaScript // main.js extractorWorker.onmessage = e => { // here the features received can be visualised inferenceWorker.postMessage(e.data) // send features to be used by the model } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.