diff --git a/samples/KristofferStrube.Blazor.WebAudio.WasmExample/Pages/RecordMediaStream.razor b/samples/KristofferStrube.Blazor.WebAudio.WasmExample/Pages/RecordMediaStream.razor
index a166bf3..50ccafd 100644
--- a/samples/KristofferStrube.Blazor.WebAudio.WasmExample/Pages/RecordMediaStream.razor
+++ b/samples/KristofferStrube.Blazor.WebAudio.WasmExample/Pages/RecordMediaStream.razor
@@ -25,13 +25,23 @@
}
else if (peakFrequencyCount > 0)
{
- Average Max Peak: @(Math.Round(peakFrequencySum / peakFrequencyCount, 0)) Hz
+
+
+
+
+
+
+
+
+
+
+ Average Max Peak: @(Math.Round(peakFrequencySum / peakFrequencyCount, 0)) Hz
}
else if (audioBuffer is not null)
{
-
+
}
else if (mediaStream is null)
{
@@ -67,7 +77,6 @@ else
private MediaDevices? mediaDevices;
private string? error;
private byte[] frequencyMeasurements = Array.Empty();
- private bool makeMeasurements = false;
private MediaStream? mediaStream;
private List<(string label, string id)> audioOptions = new();
private string? selectedAudioSource;
@@ -75,6 +84,11 @@ else
private double peakFrequencyCount = 0;
bool recording = false;
+ double offset = 0;
+ double duration = 0;
+
+ float playbackRate = 1;
+
MediaRecorder? recorder;
EventListener? dataAvailableEventListener;
List blobsRecorded = new();
@@ -187,7 +201,7 @@ else
await using AudioBufferSourceNode sourceNode = await AudioBufferSourceNode.CreateAsync(JSRuntime, context, new()
{
Buffer = audioBuffer,
- PlaybackRate = 2
+ PlaybackRate = playbackRate
});
analyser = await context.CreateAnalyserAsync();
@@ -196,25 +210,35 @@ else
await analyser.ConnectAsync(destination);
int bufferLength = (int)await analyser.GetFrequencyBinCountAsync();
- var frequencyDataArray = await Uint8Array.CreateAsync(JSRuntime, bufferLength);
+ await using var frequencyDataArray = await Uint8Array.CreateAsync(JSRuntime, bufferLength);
var sampleRate = await context.GetSampleRateAsync();
var fftSize = await analyser.GetFftSizeAsync();
+ bool makeMeasurements;
await using EventListener endedListener = await EventListener.CreateAsync(JSRuntime, _ =>
{
makeMeasurements = false;
});
await sourceNode.AddOnEndedEventListenerAsync(endedListener);
- await sourceNode.StartAsync();
+ await sourceNode.StartAsync(when: 0, offset, duration);
+ peakFrequencySum = 0;
+ peakFrequencyCount = 1;
makeMeasurements = true;
while (makeMeasurements)
{
await analyser.GetByteFrequencyDataAsync(frequencyDataArray);
- frequencyMeasurements = await frequencyDataArray.GetAsArrayAsync();
+ try
+ {
+ frequencyMeasurements = await frequencyDataArray.GetAsArrayAsync();
+ }
+ catch (Exception)
+ {
+ Console.WriteLine("Attempted to deserialize an invalid array.");
+ }
byte largestMeasurement = frequencyMeasurements.Max();
var largestFrequencyIndex = frequencyMeasurements.ToList().IndexOf(largestMeasurement);
@@ -225,9 +249,14 @@ else
}
}
+ public async Task MakePlaybackMatchFrequency(float frequency)
+ {
+ playbackRate = (float)(playbackRate * frequency / (peakFrequencySum / peakFrequencyCount));
+ await AnalyseFrequency();
+ }
+
async Task StopAudioTrack()
{
- makeMeasurements = false;
if (mediaStream is null) return;
var audioTrack = (await mediaStream.GetAudioTracksAsync()).FirstOrDefault();
if (audioTrack is not null)
diff --git a/samples/KristofferStrube.Blazor.WebAudio.WasmExample/Shared/AudioSlicer.razor.cs b/samples/KristofferStrube.Blazor.WebAudio.WasmExample/Shared/AudioSlicer.razor.cs
index fb0775b..547d5d4 100644
--- a/samples/KristofferStrube.Blazor.WebAudio.WasmExample/Shared/AudioSlicer.razor.cs
+++ b/samples/KristofferStrube.Blazor.WebAudio.WasmExample/Shared/AudioSlicer.razor.cs
@@ -34,6 +34,18 @@ public partial class AudioSlicer : ComponentBase, IDisposable
[Parameter]
public bool PlaySoundWhenEndingMark { get; set; } = true;
+ [Parameter]
+ public double MarkedOffset { get; set; }
+
+ [Parameter]
+ public EventCallback MarkedOffsetChanged { get; set; }
+
+ [Parameter]
+ public double MarkedDuration { get; set; }
+
+ [Parameter]
+ public EventCallback MarkedDurationChanged { get; set; }
+
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (!firstRender)
@@ -52,13 +64,11 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
for (ulong i = 0; i < length; i += samples)
{
+ // We intentionally only take 1 value from each sample slice as we only need this for a visualization
float amplitude = 0;
- for (ulong j = 0; j < samples && j + i < length; j++)
+ for (ulong k = 0; k < numberOfChannels; k++)
{
- for (ulong k = 0; k < numberOfChannels; k++)
- {
- amplitude += await data[k].AtAsync((long)(i + j));
- }
+ amplitude += await data[k].AtAsync((long)i);
}
amplitudes.Add(amplitude / samples / numberOfChannels);
}
@@ -142,14 +152,18 @@ private async Task PlayMarkedSound()
await using AudioDestinationNode destination = await context.GetDestinationAsync();
await using AudioNode __ = await source.ConnectAsync(destination);
- double duration = await AudioBuffer.GetDurationAsync();
+ double bufferDuration = await AudioBuffer.GetDurationAsync();
double left = start < end ? start : end;
double right = end < start ? start : end;
- await source.StartAsync(0, left * duration, (right - left) * duration);
+ double offset = left * bufferDuration;
+ double duration = (right - left) * bufferDuration;
+
+ await source.StartAsync(0, offset, duration);
- await Task.Delay(10_000);
+ await MarkedOffsetChanged.InvokeAsync(offset);
+ await MarkedDurationChanged.InvokeAsync(duration);
}
private async Task UpdateEnd(double x)