Audiowave на сервере и фронте

Рейтинг: 1Ответов: 1Опубликовано: 16.05.2023

На сервере audiowave файла формирует команда:

ffprobe -hide_banner -v error -f lavfi -i amovie=input.wav,astats=metadata=1:reset=1 -show_entries frame=pkt_pts_time:frame_tags=lavfi.astats.Overall.RMS_level -of csv=p=0

На фронте (JS) у меня есть ArrayBuffer, но я не понимаю, как мне на выходе при его обработке получить тот же результат, что и у кода выше?

Я не очень хорошо знаком с pyton, поэтому не знаю, как строка обрабатывает данные. Есть ли какие-то примеры обработки звука, чтобы audiowave на фронте (Js) и на бэка (Py) были одинаковы или хотя бы приближены друг к другу.

На фронте сейчас обрабатывается вот так:

    const samples = 70;
    const filterFromN = n => {
        if (n === 0) return 0.04;
        return 1 - Number(n / maxHz).minmax(0.04, 1); //1 - макс высота блока, 0.04 - мин высота блока (рассчитывается от высоты canvas, в котором рисуется)
    };
    rawData = rawData.map(n => Math.abs(n));
    const blockSize = Math.floor(rawData.length / samples);
    if (blockSize === 0) return rawData.map(filterFromN);
    const filteredData = [];
    for (let i = 0; i < samples; i++) {
        let blockStart = blockSize * i;
        let sum = 0;
        for (let j = 0; j < blockSize; j++) {
            sum = sum + Math.abs(rawData[blockStart + j])
        }
        filteredData.push(sum / blockSize);
    }

    return filteredData.map(filterFromN)

Впервые работаю со звуком, поэтому моё текущее решение может оказаться тупым, заранее извиняюсь.

Ответы

▲ 0

Результат вот такой фильтрации оцень сильно похож на вывод с бэка, но есть проблема с количеством сэмплов. Все ещё не очень понятно, как ffmpeg определяет их количество, потому что иногда приходит 100, а иногда 40.

const filter = (audioBuffer) => {
        const samples = 140;

        const rawData = audioBuffer.getChannelData(0);
        const filteredData = [];
        const blockSize = Math.floor(rawData.length / samples );
        for (let i = 0; i < samples; i++) {
            let blockStart = blockSize * i;
            filteredData.push(
                getDecibels(
                    RML_LEVEL(rawData.slice(
                        blockStart,
                        blockStart + blockSize
                    ))
                )
            );
        }
        return filteredData;
    }