Blazor 在没有文件的情况下播放生成的声音

Blazor play generated sound without file

在 Blazor 项目中,我生成 sound/noise 信号作为 @DanW 的粉红噪声 example,生成 double[] 值介于 -1.0 - 1.0 之间。是否可以在浏览器中直接将此数组作为音频播放?到目前为止,我所发现的关于 sound/audio 和浏览器的所有信息都是从现有文件中播放音频。

编辑:我正在使用 C# 中的一些本机 dll 进行一些过滤,并且在 C# 中比在 javascript 中更舒服,因此尝试在 C# 中而不是在 javascript 中完成大部分工作。

我使用 Java(Spring 框架)生成文件并通过 Thymeleaf 将原始 PCM 下载到 html 中的 Java 脚本变量没有问题,并且通过网络音频 API 播放它们,例如,使用 AudioBuffer 对象。 Blazor 是否有某些方面可以防止或禁止使用 Web 音频对象? IDK 如何在存在指定不同语言的脚本标签时工作 HTML,如果它们之间存在通信方式。

Blazor 没有预先打包声音编辑功能,但现在有 JS 隔离,这意味着组件可以加载所需的 JS 模块。

我的建议是使用 WebAudio API 等在定制组件的集合中直接在 JavaScript 中完成所有音频内容。

您可以使用 C# 生成波形等,但我不确定这样做有什么好处,除非您想使用现有的 C# 库。

所以我设法使用 WebAudio API 弄清楚如何:

Javascript:

// for cross browser compatibility
const AudioContext = window.AudioContext || window.webkitAudioContext;
audioCtx = {};

function initAudio() {
    // creation of audio context cannot not be done on loading file, must be done afterwards
    audioCtx = new AudioContext();
    return audioCtx.sampleRate;
}

// floats is a 1-D array with channel data after each other:
// ch1 = floats.slice(0,nSamples)
// ch2 = floats.slice(nSamples,nSamples*2)
function playNoise(floats, nChannels) {
    const bufferSize = floats.length / nChannels;
    let arrayBuffer = audioCtx.createBuffer(nChannels, bufferSize, audioCtx.sampleRate);

    for (var i = 0; i < nChannels; i++) {
        let f32arr = new Float32Array(floats.slice(i * bufferSize, (i + 1) * bufferSize));
        arrayBuffer.copyToChannel(f32arr, i, 0);
    }

    // Creating AudioBufferSourceNode
    let noise = audioCtx.createBufferSource();
    noise.buffer = arrayBuffer;
    noise.connect(audioCtx.destination);
    noise.start();
    return true;
}

Blazor 页面(我使用 Blazorise (Button)):

@page "/Tests"
@inject IJSRuntime js
<h3>Test</h3>
<Button Clicked="@(async () => await TestJS())" Color="Color.Primary">Test JS</Button>

@code {
    double fs;
    protected override async Task OnInitializedAsync()
    {
        fs = await js.InvokeAsync<double>("initAudio");
        await base.OnInitializedAsync();
    }

    private async Task TestJS()
    {
        var nChannels = 2;
        var nSecs = 5;
        var nSampels = (int)fs * nSecs * nChannels;
        var floats = new float[nSampels];
        var freq = 440;
        for (int i = 0; i < nSampels / nChannels; i++)
        {
            floats[i] = (float)Math.Sin(i * freq * 2 * Math.PI / fs);
            floats[i + nSampels / 2] = (float)Math.Sin(i * freq * 2 * 2 * Math.PI / fs);
        }
        var ok = await js.InvokeAsync<bool>("playNoise", floats, nChannels);
    }
}

该按钮在左声道(通道 1)中播放 440 Hz 的音调,在右声道(通道 2)中播放 880 Hz 的音调。

编辑:采样率不必与 AudioContext 中的相同。检查 here 的规格。