Skip to content

Commit

Permalink
Separate AmplitudeProcessor from TrackSDL3
Browse files Browse the repository at this point in the history
  • Loading branch information
hwsmm committed Sep 6, 2024
1 parent d2cdee0 commit e844ea1
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 52 deletions.
2 changes: 1 addition & 1 deletion osu.Framework/Audio/Mixing/SDL3/ISDL3AudioChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ internal interface ISDL3AudioChannel : IAudioChannel
/// <summary>
/// Returns remaining audio samples.
/// </summary>
/// <param name="data">Audio data needs to be put here. Length of this determines how much data needs to be filled.</param>
/// <param name="data">Channel puts audio in this array. Length of this determines how much data needs to be filled.</param>
/// <returns>Sample count</returns>
int GetRemainingSamples(float[] data);

Expand Down
52 changes: 52 additions & 0 deletions osu.Framework/Audio/SDL3AmplitudeProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using NAudio.Dsp;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions;

namespace osu.Framework.Audio
{
internal class SDL3AmplitudeProcessor
{
/// <summary>
/// The most recent amplitude data. Note that this is updated on an ongoing basis and there is no guarantee it is in a consistent (single sample) state.
/// If you need consistent data, make a copy of FrequencyAmplitudes while on the audio thread.
/// </summary>
public ChannelAmplitudes CurrentAmplitudes { get; private set; } = ChannelAmplitudes.Empty;

private Complex[] fftSamples = new Complex[ChannelAmplitudes.AMPLITUDES_SIZE * 2];

Check failure on line 19 in osu.Framework/Audio/SDL3AmplitudeProcessor.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Field can be made readonly in osu.Framework\Audio\SDL3AmplitudeProcessor.cs on line 19
private float[] fftResult = new float[ChannelAmplitudes.AMPLITUDES_SIZE];

Check failure on line 20 in osu.Framework/Audio/SDL3AmplitudeProcessor.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Field can be made readonly in osu.Framework\Audio\SDL3AmplitudeProcessor.cs on line 20

public void Update(float[] samples, int channels)
{
if (samples.Length / channels < ChannelAmplitudes.AMPLITUDES_SIZE)
return; // not enough data

float leftAmplitude = 0;
float rightAmplitude = 0;
int secondCh = channels < 2 ? 0 : 1;
int fftIndex = 0;

for (int i = 0; i < samples.Length; i += channels)
{
leftAmplitude = Math.Max(leftAmplitude, Math.Abs(samples[i]));
rightAmplitude = Math.Max(rightAmplitude, Math.Abs(samples[i + secondCh]));

if (fftIndex < fftSamples.Length)
{
fftSamples[fftIndex].Y = 0;
fftSamples[fftIndex++].X = samples[i] + samples[i + secondCh];
}
}

FastFourierTransform.FFT(true, (int)Math.Log2(fftSamples.Length), fftSamples);

for (int i = 0; i < fftResult.Length; i++)
fftResult[i] = fftSamples[i].ComputeMagnitude();

CurrentAmplitudes = new ChannelAmplitudes(Math.Min(1f, leftAmplitude), Math.Min(1f, rightAmplitude), fftResult);
}
}
}
57 changes: 6 additions & 51 deletions osu.Framework/Audio/Track/TrackSDL3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NAudio.Dsp;
using osu.Framework.Audio.Mixing.SDL3;
using osu.Framework.Extensions;
using osu.Framework.Logging;
Expand Down Expand Up @@ -100,57 +99,12 @@ void ISDL3AudioDataReceiver.GetMetaData(int bitrate, double length, long byteLen
}
}

private volatile bool amplitudeRequested;
private double lastTime;

private ChannelAmplitudes currentAmplitudes = ChannelAmplitudes.Empty;
private float[]? samples;
private Complex[]? fftSamples;
private float[]? fftResult;

public override ChannelAmplitudes CurrentAmplitudes
{
get
{
if (!amplitudeRequested)
amplitudeRequested = true;

return isRunning ? currentAmplitudes : ChannelAmplitudes.Empty;
}
}

private void updateCurrentAmplitude()
{
samples ??= new float[(int)(player.SrcRate * (1f / 60)) * player.SrcChannels];
fftSamples ??= new Complex[ChannelAmplitudes.AMPLITUDES_SIZE * 2];
fftResult ??= new float[ChannelAmplitudes.AMPLITUDES_SIZE];

player.Peek(samples, lastTime);

float leftAmplitude = 0;
float rightAmplitude = 0;
int secondCh = player.SrcChannels < 2 ? 0 : 1;
int fftIndex = 0;
private SDL3AmplitudeProcessor? amplitudeProcessor;

for (int i = 0; i < samples.Length; i += player.SrcChannels)
{
leftAmplitude = Math.Max(leftAmplitude, Math.Abs(samples[i]));
rightAmplitude = Math.Max(rightAmplitude, Math.Abs(samples[i + secondCh]));

if (fftIndex < fftSamples.Length)
{
fftSamples[fftIndex].Y = 0;
fftSamples[fftIndex++].X = samples[i] + samples[i + secondCh];
}
}

FastFourierTransform.FFT(true, (int)Math.Log2(fftSamples.Length), fftSamples);

for (int i = 0; i < fftResult.Length; i++)
fftResult[i] = fftSamples[i].ComputeMagnitude();

currentAmplitudes = new ChannelAmplitudes(Math.Min(1f, leftAmplitude), Math.Min(1f, rightAmplitude), fftResult);
}
public override ChannelAmplitudes CurrentAmplitudes => (amplitudeProcessor ??= new SDL3AmplitudeProcessor()).CurrentAmplitudes;

protected override void UpdateState()
{
Expand All @@ -176,12 +130,13 @@ protected override void UpdateState()
player.FillRequiredSamples();
}

// Not sure if I need to split this up to another class since this feature is only exclusive to Track
if (amplitudeRequested && isRunning && Math.Abs(currentTime - lastTime) > 1000.0 / 60.0)
if (amplitudeProcessor != null && isRunning && Math.Abs(currentTime - lastTime) > 1000.0 / 60.0)
{
lastTime = currentTime;
samples ??= new float[(int)(player.SrcRate * (1f / 60)) * player.SrcChannels];
player.Peek(samples, lastTime);

updateCurrentAmplitude();
amplitudeProcessor.Update(samples, player.SrcChannels);
}
}

Expand Down

0 comments on commit e844ea1

Please sign in to comment.