Skip to content

Commit

Permalink
Updated Recorder with adjust buttons for matching a frequency.
Browse files Browse the repository at this point in the history
  • Loading branch information
KristofferStrube committed Aug 27, 2024
1 parent 8bfcd2d commit 30669d0
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,23 @@
}
else if (peakFrequencyCount > 0)
{
<span>Average Max Peak: @(Math.Round(peakFrequencySum / peakFrequencyCount, 0)) Hz</span>
<button class="btn btn-primary" @onclick="AnalyseFrequency">Analyze</button><br />

<label for="playbackRate">Playback Rate</label>
<input id="playbackRate" @bind-value=playbackRate />
<button class="btn btn-primary btn-sm" @onclick="() => MakePlaybackMatchFrequency(220)">Match 220 Hz</button>
<button class="btn btn-primary btn-sm" @onclick="() => MakePlaybackMatchFrequency(440)">Match 440 Hz</button>
<button class="btn btn-primary btn-sm" @onclick="() => MakePlaybackMatchFrequency(880)">Match 880 Hz</button>
<button class="btn btn-primary btn-sm" @onclick="() => MakePlaybackMatchFrequency(1760)">Match 1760 Hz</button>
<br />

<span>Average Max Peak: @(Math.Round(peakFrequencySum / peakFrequencyCount, 0)) Hz</span><br />
<Plot Data="frequencyMeasurements" />
}
else if (audioBuffer is not null)
{
<button class="btn btn-primary" @onclick="AnalyseFrequency">Analyze</button>
<AudioSlicer AudioBuffer="audioBuffer" />
<AudioSlicer AudioBuffer="audioBuffer" @bind-MarkedOffset=offset @bind-MarkedDuration=duration />
}
else if (mediaStream is null)
{
Expand Down Expand Up @@ -67,14 +77,18 @@ else
private MediaDevices? mediaDevices;
private string? error;
private byte[] frequencyMeasurements = Array.Empty<byte>();
private bool makeMeasurements = false;
private MediaStream? mediaStream;
private List<(string label, string id)> audioOptions = new();
private string? selectedAudioSource;
private double peakFrequencySum = 0;
private double peakFrequencyCount = 0;
bool recording = false;

double offset = 0;
double duration = 0;

float playbackRate = 1;

MediaRecorder? recorder;
EventListener<BlobEvent>? dataAvailableEventListener;
List<Blob> blobsRecorded = new();
Expand Down Expand Up @@ -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();
Expand All @@ -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<Event> endedListener = await EventListener<Event>.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);
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<double> MarkedOffsetChanged { get; set; }

[Parameter]
public double MarkedDuration { get; set; }

[Parameter]
public EventCallback<double> MarkedDurationChanged { get; set; }

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (!firstRender)
Expand All @@ -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);
}
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 30669d0

Please sign in to comment.