Skip to content
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

Retrieve tags from Bass tracks when available #5627

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions osu.Framework.Tests/Audio/TrackBassTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,19 @@ public void TestCurrentTimeUpdatedAfterInlineSeek()
Assert.That(track.CurrentTime, Is.EqualTo(20000).Within(100));
}

[Test]
public void TestTagReader()
{
var tags = track.Tags;

Assert.That(tags, Is.Not.Null);
Assert.That(tags.Artist, Is.EqualTo("osu-framework"));
Assert.That(tags.Album, Is.EqualTo("osu-framework"));
Assert.That(tags.Genre, Is.EqualTo("tunes"));
Assert.That(tags.Year, Is.EqualTo(2008));
Assert.That(tags.Title, Is.EqualTo("sample-track"));
}

private void takeEffectsAndUpdateAfter(int after)
{
bass.Update();
Expand Down
Binary file modified osu.Framework.Tests/Resources/Tracks/sample-track.mp3
Binary file not shown.
5 changes: 5 additions & 0 deletions osu.Framework/Audio/Track/ITrack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ public interface ITrack : IAdjustableClock, IHasAmplitudes, IAdjustableAudioComp
/// </summary>
int? Bitrate { get; }

/// <summary>
/// The ID3 tags contained in this track's metadata.
/// </summary>
Tags? Tags { get; }
Comment on lines +49 to +52
Copy link
Collaborator

@bdach bdach Jan 16, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm really not sure if we want this on Track. Especially so if it's going to not be implemented for anything but TrackBass.

Alternative would be something like

public interface ITaggedTrack
{
    Tags Tags { get; }
}

which could only be applied to TrackBass, but that likely causes trouble with DrawableTrack (the inner track is private, so you wouldn't be able to access the tags otherwise).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made sense in my head as tags can be present on the track regardless of implementation (Bass or otherwise).

DrawableTrack's inner track could probably be public since it's already readonly?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but layering wise I'm not sure it fits smack dab in the middle of the rest of the audio subsystem.

I'm just mostly pondering. Need more opinions on this for sure before proceeding in any particular direction.

Copy link
Member

@peppy peppy Jan 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember there being an overhead with tag retrieval, in stable it’s only requested in the editor to avoid this.
Will need to check if this is still the case.

On actually inspecting the code, it looks to be on-demand so this shouldn't be an issue.


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

namespace osu.Framework.Audio.Track
{
/// <summary>
/// A container for audio track metadata.
/// </summary>
public class Tags
{
public string? Title { get; set; }

public string? Artist { get; set; }

public string? Album { get; set; }

public int? Year { get; set; }

public string? Genre { get; set; }
}
}
4 changes: 4 additions & 0 deletions osu.Framework/Audio/Track/Track.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public abstract class Track : AdjustableAudioComponent, ITrack, IAudioChannel

public virtual bool Looping { get; set; }

public Tags? Tags => GetTags();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're going to go as far as having a property, it should probably cache so they are only retrieved once.


public string Name { get; }

protected Track(string name)
Expand Down Expand Up @@ -119,6 +121,8 @@ public virtual double Rate

public virtual ChannelAmplitudes CurrentAmplitudes { get; } = ChannelAmplitudes.Empty;

protected virtual Tags? GetTags() => null;

protected override void UpdateState()
{
FrameStatistics.Increment(StatisticsCounterType.Tracks);
Expand Down
24 changes: 24 additions & 0 deletions osu.Framework/Audio/Track/TrackBass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,30 @@ public override async Task<bool> SeekAsync(double seek)
return conservativeClamped == seek;
}

protected override Tags? GetTags()
{
var tags = TagReader.Read(activeStream);

if (tags == null)
return null;

var parsed = new Tags
{
Artist = tags.Artist?.Trim()!,
Title = tags.Title,
Album = tags.Album,
Genre = tags.Genre,
};

if (string.IsNullOrEmpty(parsed.Artist))
parsed.Artist = tags.AlbumArtist;

if (int.TryParse(tags.Year, out int year))
parsed.Year = year;

return parsed;
}

private void seekInternal(double seek)
{
double clamped = Math.Clamp(seek, 0, Length);
Expand Down
1 change: 1 addition & 0 deletions osu.Framework/Graphics/Audio/DrawableTrack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public double Length
}

public int? Bitrate => track.Bitrate;
public Tags? Tags => track.Tags;

public bool IsRunning => track.IsRunning;

Expand Down