Skip to content

Commit

Permalink
Add TrackLoudness (BASSloud)
Browse files Browse the repository at this point in the history
Co-authored-by: smallketchup82 <[email protected]>
  • Loading branch information
hwsmm and smallketchup82 committed May 12, 2024
1 parent 9c6dee5 commit 88450e1
Showing 1 changed file with 141 additions and 0 deletions.
141 changes: 141 additions & 0 deletions osu.Framework/Audio/Track/TrackLoudness.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// 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 System.Buffers;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using ManagedBass;
using ManagedBass.Loud;

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Code Quality

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Code Quality

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Build only (iOS)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Build only (iOS)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Linux, ubuntu-latest, Debug, MultiThreaded)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Linux, ubuntu-latest, Debug, MultiThreaded)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (macOS, macos-latest, Debug, MultiThreaded)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (macOS, macos-latest, Debug, MultiThreaded)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Linux, ubuntu-latest, Debug, SingleThread)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Linux, ubuntu-latest, Debug, SingleThread)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (macOS, macos-latest, Debug, SingleThread)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (macOS, macos-latest, Debug, SingleThread)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Linux, ubuntu-latest, Release, SingleThread)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Linux, ubuntu-latest, Release, SingleThread)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Linux, ubuntu-latest, Release, MultiThreaded)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Linux, ubuntu-latest, Release, MultiThreaded)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Windows, windows-latest, Debug, MultiThreaded)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Windows, windows-latest, Debug, MultiThreaded)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Build only (Android)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Build only (Android)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Windows, windows-latest, Debug, SingleThread)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)

Check failure on line 10 in osu.Framework/Audio/Track/TrackLoudness.cs

View workflow job for this annotation

GitHub Actions / Test (Windows, windows-latest, Debug, SingleThread)

The type or namespace name 'Loud' does not exist in the namespace 'ManagedBass' (are you missing an assembly reference?)
using osu.Framework.Audio.Callbacks;
using osu.Framework.Extensions;
using osu.Framework.Logging;

namespace osu.Framework.Audio.Track
{
/// <summary>
/// Measures loudness of audio samples.
/// </summary>
public class TrackLoudness : IDisposable
{
private Stream? data;

private readonly Task readTask;

private readonly CancellationTokenSource cancelSource = new CancellationTokenSource();

private float? integratedLoudness;

/// <summary>
/// Measures loudness from provided audio data.
/// </summary>
/// <param name="data">
/// The sample data stream.
/// The <see cref="TrackLoudness"/> will take ownership of this stream and dispose it when done reading track data.
/// If null, loudness won't get calculated.
/// </param>
public TrackLoudness(Stream? data)
{
this.data = data;

readTask = Task.Run(() =>
{
if (data == null)
return;

if (Bass.CurrentDevice < 0)
{
Logger.Log("Failed to measure loudness as no bass device is available.");
return;
}

FileCallbacks fileCallbacks = new FileCallbacks(new DataStreamFileProcedures(data));

int decodeStream = Bass.CreateStream(StreamSystem.NoBuffer, BassFlags.Decode | BassFlags.Float, fileCallbacks.Callbacks, fileCallbacks.Handle);

if (decodeStream == 0)
{
Logger.Log($"Bass failed to create a stream while trying to measure loudness: {Bass.LastError}");
fileCallbacks.Dispose();
return;
}

byte[] buffer = ArrayPool<byte>.Shared.Rent(20000);

try
{
int loudHandle = BassLoud.Start(decodeStream, BassFlags.BassLoudnessIntegrated | BassFlags.BassLoudnessAutofree, 0);

if (loudHandle == 0)
{
Logger.Log($"Failed to start BassLoud: {Bass.LastError}");
return;
}

while (Bass.ChannelGetData(decodeStream, buffer, buffer.Length) >= 0)
{
}

float integratedLoudness = 1;
bool gotLevel = BassLoud.GetLevel(loudHandle, BassFlags.BassLoudnessIntegrated, ref integratedLoudness);

if (!gotLevel)
{
Logger.Log($"Failed to get loudness level: {Bass.LastError}");
return;
}

if (integratedLoudness < 0)
this.integratedLoudness = integratedLoudness;
}
finally
{
Bass.StreamFree(decodeStream);
fileCallbacks.Dispose();
data.Dispose();

ArrayPool<byte>.Shared.Return(buffer);
}
}, cancelSource.Token);
}

/// <summary>
/// Returns integrated loudness.
/// </summary>
public async Task<float?> GetIntegratedLoudnessAsync()
{
await readTask.ConfigureAwait(false);

return integratedLoudness;
}

/// <summary>
/// Returns integrated loudness.
/// </summary>
public float? GetIntegratedLoudness() => GetIntegratedLoudnessAsync().GetResultSafely();

protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
cancelSource.Cancel();
cancelSource.Dispose();
integratedLoudness = null;

data?.Dispose();
data = null;

disposedValue = true;
}
}

private bool disposedValue;

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}

0 comments on commit 88450e1

Please sign in to comment.