Classification of existing audio files on desktop

I am hoping to use Edge Impulse to classify audio data that I have already collected. The data is from tropical forests, and I am looking to classify gunshots to look at hunting pressure.

I have started to train a model, and I followed the instructions for running the impulse locally - https://docs.edgeimpulse.com/docs/running-your-impulse-locally . From this I see I can only make classifications on my terminal by inputting numeric arrays, and I’m not sure how to take this further. What I want to do is run the impulse from my computer over 1000s of wav files stored in folders, and get an output of classifications. What is the best way of doing this? I don’t have high level computing skills beyond R and basic Python.

Thanks!

Hi @LydiaK, I don’t have an example for Python easily, but you can do it with Node.js (and you could call Node from Python for example).

  1. Export as WebAssembly.
  2. In the same folder create a new file called run-impulse.js and add:
// Load the inferencing WebAssembly module
const Module = require('./edge-impulse-standalone');
const WaveFile = require('wavefile').WaveFile;
const fs = require('fs');

// Classifier module
let classifierInitialized = false;
Module.onRuntimeInitialized = function() {
    classifierInitialized = true;
};

class EdgeImpulseClassifier {
    _initialized = false;

    init() {
        if (classifierInitialized === true) return Promise.resolve();

        return new Promise((resolve) => {
            Module.onRuntimeInitialized = () => {
                resolve();
                classifierInitialized = true;
            };
        });
    }

    classify(rawData, debug = false) {
        if (!classifierInitialized) throw new Error('Module is not initialized');

        const obj = this._arrayToHeap(rawData);
        let ret = Module.run_classifier(obj.buffer.byteOffset, rawData.length, debug);
        Module._free(obj.ptr);

        if (ret.result !== 0) {
            throw new Error('Classification failed (err code: ' + ret.result + ')');
        }

        let jsResult = {
            anomaly: ret.anomaly,
            results: []
        };

        for (let cx = 0; cx < ret.classification.size(); cx++) {
            let c = ret.classification.get(cx);
            jsResult.results.push({ label: c.label, value: c.value });
        }

        return jsResult;
    }

    _arrayToHeap(data) {
        let typedArray = new Float32Array(data);
        let numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT;
        let ptr = Module._malloc(numBytes);
        let heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, numBytes);
        heapBytes.set(new Uint8Array(typedArray.buffer));
        return { ptr: ptr, buffer: heapBytes };
    }
}

if (!process.argv[2]) {
    return console.error('Requires one parameter (a WAV file)');
}

// Initialize the classifier, and invoke with the argument passed in
let classifier = new EdgeImpulseClassifier();
classifier.init().then(() => {
    // Read the WAV file
    const wav = new WaveFile(fs.readFileSync(process.argv[2]));

    // Parse the WAV file
    let fmt = wav.fmt;

    let totalSamples = wav.data.samples.length / (fmt.bitsPerSample / 8);

    let dataBuffers = [];

    for (let sx = 0; sx < totalSamples; sx += fmt.numChannels) {
        try {
            let sum = 0;

            for (let channelIx = 0; channelIx < fmt.numChannels; channelIx++) {
                sum += wav.getSample(sx + channelIx);
            }

            dataBuffers.push(sum / fmt.numChannels);
        }
        catch (ex) {
            console.error('failed to call getSample() on WAV file', sx, ex);
            process.exit(1);
        }
    }

    let result = classifier.classify(dataBuffers);

    console.log(result);
}).catch(err => {
    console.error('Failed to initialize classifier', err);
});
  1. Open a command prompt or terminal window, navigate to the same folder and run:
npm install wavefile
  1. Then you can classify any WAV file via:
node run-impulse.js /Users/janjongboom/Downloads/jan.1g52kk9k.wav.1g52l3ea.s29.wav

Which will return something like:

{
  anomaly: 0,
  results: [
    { label: 'jan', value: 0.9921875 },
    { label: 'noise', value: 0 },
    { label: 'other', value: 0.0078125 }
  ]
}

Hope this helps!

2 Likes

Hi @janjongboom thanks so much for your quick response and for this code! I will try this out!

1 Like