-
Notifications
You must be signed in to change notification settings - Fork 0
Improvements for audio normalization #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
b81277f
e58115f
6f2d873
663aa15
729f22d
baede41
2ce022d
89aabae
6182878
46f11c7
7abcb5f
953d661
b5ceb48
7b9360e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,10 +2,7 @@ | |
| // See the LICENCE file in the repository root for full licence text. | ||
|
|
||
| using System; | ||
| using System.Linq; | ||
| using ManagedBass; | ||
| using ManagedBass.Fx; | ||
| using osu.Framework.Audio.Mixing; | ||
| using osu.Framework.Audio.Track; | ||
| using osu.Framework.Logging; | ||
| using osu.Game.Beatmaps; | ||
| using osu.Game.Database; | ||
|
|
@@ -16,7 +13,7 @@ namespace osu.Game.Audio | |
| /// <summary> | ||
| /// Audio Normalization Manager | ||
| /// </summary> | ||
| public class AudioNormalization : EmbeddedObject, IAudioNormalization, IEquatable<AudioNormalization> | ||
| public class AudioNormalization : EmbeddedObject, IEquatable<AudioNormalization> | ||
| { | ||
| /// <summary> | ||
| /// The target level for audio normalization | ||
|
|
@@ -57,9 +54,9 @@ public AudioNormalization(BeatmapInfo beatmapInfo, BeatmapSetInfo beatmapSetInfo | |
| return; | ||
| } | ||
|
|
||
| filepath = realmFileStore.Storage.GetFullPath(filepath); | ||
| using TrackLoudness loudness = new TrackLoudness(realmFileStore.Storage.GetStream(filepath)); | ||
|
|
||
| float? integratedLoudness = new BassAudioNormalization(filepath).IntegratedLoudness; | ||
| float? integratedLoudness = loudness.GetIntegratedLoudness(); | ||
|
|
||
| if (integratedLoudness == null) | ||
| { | ||
|
|
@@ -93,57 +90,9 @@ public void PopulateSet(BeatmapInfo beatmapInfo, BeatmapSetInfo beatmapSetInfo) | |
| } | ||
|
|
||
| /// <summary> | ||
| /// Convert integrated loudness to a volume offset | ||
| /// A volume offset that can be applied upon audio to reach <see cref="TARGET_LEVEL"/> (converted from integrated loudness). | ||
| /// </summary> | ||
| /// <param name="integratedLoudness">The integrated loudness value</param> | ||
| /// <returns>The volume offset needed to reach <see cref="TARGET_LEVEL"/></returns> | ||
| public static float IntegratedLoudnessToVolumeOffset(float integratedLoudness) => (float)Math.Pow(10, (TARGET_LEVEL - integratedLoudness) / 20); | ||
|
|
||
| /// <summary> | ||
| /// Get the loudness values of a <see cref="BeatmapInfo"/> and apply the audio normalization effect to an <see cref="IAudioMixer"/> | ||
| /// </summary> | ||
| /// <param name="beatmapInfo">The <see cref="BeatmapInfo"/> to get the loudness values of</param> | ||
| /// <param name="mixer">The <see cref="IAudioMixer"/> to apply the effect on</param> | ||
| public static void AddAudioNormalization(BeatmapInfo beatmapInfo, IAudioMixer mixer) | ||
| { | ||
| AudioNormalization? audioNormalizationModule = beatmapInfo.AudioNormalization; | ||
|
|
||
| VolumeParameters volumeParameters = new VolumeParameters | ||
| { | ||
| fTarget = audioNormalizationModule?.IntegratedLoudness != null ? IntegratedLoudnessToVolumeOffset((float)audioNormalizationModule.IntegratedLoudness) : 0.8f, | ||
| fCurrent = -1.0f, | ||
| fTime = 0.3f, | ||
| lCurve = 1, | ||
| lChannel = FXChannelFlags.All | ||
| }; | ||
|
|
||
| addFx(volumeParameters, mixer); | ||
|
|
||
| Logger.Log("Normalization Status: " + (audioNormalizationModule?.IntegratedLoudness != null ? $"on ({Math.Round(IntegratedLoudnessToVolumeOffset((float)audioNormalizationModule.IntegratedLoudness) * 100)}%)" : "off")); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Add an effect to a <see cref="IAudioMixer"/>, replacing it if it already exists | ||
| /// </summary> | ||
| /// <param name="effectParameter">The <see cref="IEffectParameter"/> to add to the <paramref name="mixer"/></param> | ||
| /// <param name="mixer">The <see cref="IAudioMixer"/> to add the effect to</param> | ||
| private static void addFx(IEffectParameter effectParameter, IAudioMixer mixer) | ||
| { | ||
| IEffectParameter? effect = mixer.Effects.SingleOrDefault(e => e.FXType == effectParameter.FXType); | ||
|
|
||
| if (effect != null) | ||
| { | ||
| int i = mixer.Effects.IndexOf(effect); | ||
| mixer.Effects[i] = effectParameter; | ||
| } | ||
| else | ||
| { | ||
| mixer.Effects.Add(effectParameter); | ||
| } | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public bool Equals(IAudioNormalization? other) => other is AudioNormalization audioNormalization && Equals(audioNormalization); | ||
| public float IntegratedLoudnessInVolumeOffset => IntegratedLoudness != null ? (float)Math.Pow(10, (TARGET_LEVEL - (double)IntegratedLoudness) / 20) : 0.8f; | ||
|
hwsmm marked this conversation as resolved.
Outdated
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it'd be better to lower the global volume reduction. In my testing, turning off normalization would blast your ears since 100% volume with 0.8 is much louder than 100% with -14 LUFS. I'll probably do my own testing to find a proper value for it and consult with the core team & @nekodex about it. You can dismiss this message since its more of a note for myself. Though, nekodex, if you have any thoughts on this then do let me know |
||
|
|
||
| /// <inheritdoc /> | ||
| public bool Equals(AudioNormalization? other) => other?.IntegratedLoudness != null && IntegratedLoudness != null && Math.Abs((float)(IntegratedLoudness - other.IntegratedLoudness)) < 0.0000001; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. | ||
| // See the LICENCE file in the repository root for full licence text. | ||
|
|
||
| using osu.Framework.Audio; | ||
| using osu.Framework.Audio.Track; | ||
| using osu.Framework.Bindables; | ||
| using osu.Framework.Logging; | ||
| using osu.Game.Configuration; | ||
| using osu.Game.Overlays; | ||
|
|
||
| namespace osu.Game.Audio | ||
| { | ||
| /// <summary> | ||
| /// Provides bindables for track/sample volume. | ||
| /// </summary> | ||
| public class AudioNormalizationManager | ||
| { | ||
| private readonly Bindable<bool> beatmapHitsoundBind; | ||
|
|
||
| /// <summary> | ||
| /// Default <see cref="ITrackStore"/> will bind to this bindable. | ||
| /// <see cref="MusicController"/> updates this on every track change. | ||
| /// It's set to 0.8 by default to leave some head-room for UI effects / samples. | ||
| /// </summary> | ||
| public readonly BindableDouble TrackNormalizeVolume = new BindableDouble(0.8); | ||
|
|
||
| /// <summary> | ||
| /// Samples assigned to hitobjects needs to bind to this bindable to normalize their volume in line with track. | ||
| /// </summary> | ||
| public readonly BindableDouble SampleNormalizeVolume = new BindableDouble(1.0); | ||
|
|
||
| /// <summary> | ||
| /// Creates a new <see cref="AudioNormalizationManager"/>. | ||
| /// </summary> | ||
| /// <param name="audioManager"></param> | ||
| /// <param name="config"></param> | ||
|
hwsmm marked this conversation as resolved.
Outdated
|
||
| public AudioNormalizationManager(AudioManager audioManager, OsuConfigManager config) | ||
| { | ||
| audioManager.Tracks.AddAdjustment(AdjustableProperty.Volume, TrackNormalizeVolume); | ||
|
|
||
| beatmapHitsoundBind = config.GetBindable<bool>(OsuSetting.BeatmapHitsounds); | ||
|
|
||
| normalizeSampleIfTrue(beatmapHitsoundBind.Value); | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we only retain the relationship between tracks and hitsounds if beatmap hitsounds are turned on? Unless I'm mistaken and this does something entirely different, I think we'd want the volume offset to apply to skin hitsounds, beatmap hitsounds, and all other gameplay samples (combo sound, slider tick, etc). Though I want to mention @nekodex and get his opinion on this.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assumed that most players expect consistent hitsounds over maps if they don't have beatmap hitsounds enabled. I guess I should have discussed about this earlier.. |
||
| beatmapHitsoundBind.BindValueChanged(change => normalizeSampleIfTrue(change.NewValue)); | ||
| } | ||
|
|
||
| private void normalizeSampleIfTrue(bool value) | ||
| { | ||
| if (value) | ||
| { | ||
| SampleNormalizeVolume.BindTo(TrackNormalizeVolume); | ||
| } | ||
| else | ||
| { | ||
| SampleNormalizeVolume.UnbindFrom(TrackNormalizeVolume); | ||
| SampleNormalizeVolume.Value = 1.0; | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file was deleted.
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.