osu.Framework/Audio/Track/Waveform.cs
/// <summary>
/// Creates a new <see cref="Waveform"/> containing a specific number of data points by selecting the average value of each sampled group.
/// </summary>
/// <param name="pointCount">The number of points the resulting <see cref="Waveform"/> should contain.</param>
/// <param name="cancellationToken">The token to cancel the task.</param>
/// <returns>An async task for the generation of the <see cref="Waveform"/>.</returns>
Creates a new  containing a specific number of data points by selecting the average value of each sampled group.
Creates a new containing a specific number of data points by selecting the average value of each sampled group .
public async Task<Waveform> GenerateResampledAsync(int pointCount, CancellationToken cancellationToken = default)
        {
            if (pointCount < 0) throw new ArgumentOutOfRangeException(nameof(pointCount));
            if (readTask == null)
                return new Waveform(null);
            await readTask;
            return await Task.Run(() =>
            {
                var generatedPoints = new List<WaveformPoint>();
                float pointsPerGeneratedPoint = (float)points.Count / pointCount;
                const int kernel_width_factor = 3;
                int kernelWidth = (int)(pointsPerGeneratedPoint * kernel_width_factor) + 1;
                float[] filter = new float[kernelWidth + 1];
                for (int i = 0; i < filter.Length; ++i)
                {
                    filter[i] = (float)Blur.EvalGaussian(i, pointsPerGeneratedPoint);
                }
                for (float i = 0; i < points.Count; i += pointsPerGeneratedPoint)
                {
                    if (cancellationToken.IsCancellationRequested) break;
                    int startIndex = (int)i - kernelWidth;
                    int endIndex = (int)i + kernelWidth;
                    var point = new WaveformPoint(channels);
                    float totalWeight = 0;
                    for (int j = startIndex; j < endIndex; j++)
                    {
                        if (j < 0 || j >= points.Count) continue;
                        float weight = filter[Math.Abs(j - startIndex - kernelWidth)];
                        totalWeight += weight;
                        for (int c = 0; c < channels; c++)
                            point.Amplitude[c] += weight * points[j].Amplitude[c];
                        point.LowIntensity += weight * points[j].LowIntensity;
                        point.MidIntensity += weight * points[j].MidIntensity;
                        point.HighIntensity += weight * points[j].HighIntensity;
                    }
                    for (int c = 0; c < channels; c++)
                        point.Amplitude[c] /= totalWeight;
                    point.LowIntensity /= totalWeight;
                    point.MidIntensity /= totalWeight;
                    point.HighIntensity /= totalWeight;
                    generatedPoints.Add(point);
                }
                return new Waveform(null)
                {
                    points = generatedPoints,
                    channels = channels
                };
            }, cancellationToken);
        }
public async Task < Waveform > GenerateResampledAsync ( int pointCount , CancellationToken cancellationToken = default ) { if ( pointCount < 0 ) throw new ArgumentOutOfRangeException ( nameof ( pointCount ) ) ; if ( readTask == null ) return new Waveform ( null ) ; await readTask ; return await Task . Run ( ( ) => { var generatedPoints = new List < WaveformPoint > ( ) ; float pointsPerGeneratedPoint = ( float ) points . Count / pointCount ; const int kernel_width_factor = 3 ; int kernelWidth = ( int ) ( pointsPerGeneratedPoint * kernel_width_factor ) + 1 ; float [ ] filter = new float [ kernelWidth + 1 ] ; for ( int i = 0 ; i < filter . Length ; ++ i ) { filter [ i ] = ( float ) Blur . EvalGaussian ( i , pointsPerGeneratedPoint ) ; } for ( float i = 0 ; i < points . Count ; i += pointsPerGeneratedPoint ) { if ( cancellationToken . IsCancellationRequested ) break ; int startIndex = ( int ) i - kernelWidth ; int endIndex = ( int ) i + kernelWidth ; var point = new WaveformPoint ( channels ) ; float totalWeight = 0 ; for ( int j = startIndex ; j < endIndex ; j ++ ) { if ( j < 0 || j >= points . Count ) continue ; float weight = filter [ Math . Abs ( j - startIndex - kernelWidth ) ] ; totalWeight += weight ; for ( int c = 0 ; c < channels ; c ++ ) point . Amplitude [ c ] += weight * points [ j ] . Amplitude [ c ] ; point . LowIntensity += weight * points [ j ] . LowIntensity ; point . MidIntensity += weight * points [ j ] . MidIntensity ; point . HighIntensity += weight * points [ j ] . HighIntensity ; } for ( int c = 0 ; c < channels ; c ++ ) point . Amplitude [ c ] /= totalWeight ; point . LowIntensity /= totalWeight ; point . MidIntensity /= totalWeight ; point . HighIntensity /= totalWeight ; generatedPoints . Add ( point ) ; } return new Waveform ( null ) { points = generatedPoints , channels = channels } ; } , cancellationToken ) ; }
Creates a new  containing a specific number of data points by selecting the average value of each sampled group.
Creates a new containing a specific number of data points by selecting the average value of each sampled group .
// Determines at which width (relative to the resolution) our smoothing filter is truncated. // Should not effect overall appearance much, except when the value is too small. // A gaussian contains almost all its mass within its first 3 standard deviations, // so a factor of 3 is a very good choice here. // Means
An async task for the generation of the .
An async task for the generation of the .
pointCount
int
The number of points the resulting  should contain.
The number of points the resulting should contain .
cancellationToken
CancellationToken
The token to cancel the task.
The token to cancel the task .