In a Blazor project I generate sound/noise signals as @DanW 's pink noise example, that generates a double[]
with values between -1.0 - 1.0. Is it possible to play this array directly as audio in the browser? All I have found about sound/audio and browsers so far has been playing audio from an existing file.
EDIT: I am doing some filtering using some native dll's in C# and am more comfortable in c# than in javascript, hence trying to do most work in C# and not javascript.
So I managed with the WebAudio API to figure out how to:
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 page (I use 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);
}
}
The button plays a 440 Hz tone in the left channel (chanel 1) and a 880 Hz tone in the right channel (channel 2).
EDIT: Samplerate does not have to be the same as in the AudioContext
. Check here for specs.