Skip to content

Commit

Permalink
Don't use negative position in TrackSDL2
Browse files Browse the repository at this point in the history
  • Loading branch information
hwsmm committed Oct 3, 2023
1 parent 711035d commit a47afbd
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 89 deletions.
11 changes: 9 additions & 2 deletions osu.Framework/Audio/Track/TempoSDL2AudioPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,15 @@ public void SetTempo(double tempo)

if (Tempo == 1.0f)
{
int latency = GetTempoLatency() * 4 * SrcChannels;
StreamPosition = !ReversePlayback ? StreamPosition - latency : StreamPosition + latency;
if (AudioData != null)
{
int latency = GetTempoLatency() * 4 * SrcChannels;
long temp = !ReversePlayback ? AudioData.Position - latency : AudioData.Position + latency;

if (temp >= 0)
AudioData.Position = temp;
}

Reset(false);
soundTouch = null;
return;
Expand Down
6 changes: 3 additions & 3 deletions osu.Framework/Audio/Track/TrackSDL2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,14 +117,14 @@ internal override void OnStateChanged()
public override async Task<bool> SeekAsync(double seek)
{
double conservativeLength = Length == 0 ? double.MaxValue : Length;
double conservativeClamped = Math.Min(seek, conservativeLength);
double conservativeClamped = Math.Clamp(seek, 0, conservativeLength);

await EnqueueAction(() => seekInternal(seek)).ConfigureAwait(false);

return conservativeClamped == seek;
}

private void seekInternal(double seek) => EnqueueAction(() =>
private void seekInternal(double seek)
{
lock (syncRoot)
{
Expand All @@ -138,7 +138,7 @@ private void seekInternal(double seek) => EnqueueAction(() =>

Interlocked.Exchange(ref currentTime, player.GetCurrentTime());
}
});
}

public override void Start()
{
Expand Down
119 changes: 35 additions & 84 deletions osu.Framework/Audio/Track/TrackSDL2AudioPlayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,56 +40,12 @@ internal class TrackSDL2AudioPlayer : ResamplingPlayer, IDisposable
/// </summary>
protected MemoryStream? AudioData;

protected long NegativePosition;

/// <summary>
/// Current index in <see cref="AudioData"/>. Supports a negative value.
/// </summary>
protected long StreamPosition
{
get
{
if (NegativePosition < 0) return NegativePosition;
else return AudioData?.Position ?? 0;
}
set
{
if (AudioData == null)
return;

if (value < 0)
{
if (ReversePlayback)
throw new InvalidOperationException("You may not set negative position while reverse playback is set!");

NegativePosition = value;
AudioData.Position = 0;
}
else
{
NegativePosition = 0;
AudioData.Position = value;
}
}
}

public long AudioDataLength => AudioData?.Length ?? 0;

private bool reversePlayback;

/// <summary>
/// Play backwards if set to true.
/// </summary>
public bool ReversePlayback
{
get => reversePlayback;
set
{
if (NegativePosition > 0)
NegativePosition = 0;
reversePlayback = value;
}
}
public bool ReversePlayback { get; set; }

/// <summary>
/// Creates a new <see cref="TrackSDL2AudioPlayer"/>. Use <see cref="TempoSDL2AudioPlayer"/> if you want to adjust tempo.
Expand Down Expand Up @@ -140,9 +96,7 @@ protected override int GetRemainingRawBytes(byte[] data)
if (AudioData == null)
return 0;

long audioLen = AudioDataLength;

if (AudioDataLength <= 0)
if (AudioData.Length <= 0)
{
done = true;
return 0;
Expand All @@ -151,13 +105,13 @@ protected override int GetRemainingRawBytes(byte[] data)
if (SaveSeek > 0)
{
// set to 0 if position is over saved seek
if (StreamPosition > SaveSeek)
if (AudioData.Position > SaveSeek)
SaveSeek = 0;

// player now has audio data to play
if (audioLen > SaveSeek)
if (AudioData.Length > SaveSeek)
{
StreamPosition = SaveSeek;
AudioData.Position = SaveSeek;
SaveSeek = 0;
}

Expand All @@ -169,7 +123,7 @@ protected override int GetRemainingRawBytes(byte[] data)
bool underrun = false;
int i = 0;
int remaining = data.Length;
int put = (int)(ReversePlayback ? StreamPosition : audioLen - StreamPosition);
int put = (int)(ReversePlayback ? AudioData.Position : AudioData.Length - AudioData.Position);

if (remaining < put)
put = remaining;
Expand All @@ -178,43 +132,29 @@ protected override int GetRemainingRawBytes(byte[] data)

if (put > 0)
{
// to deal with minus seek
for (; i < put; i++)
if (ReversePlayback)
{
if (NegativePosition >= 0) break;

data[i] = 0;
NegativePosition++;
}
int frameSize = SrcChannels * 4;
byte[] temp = new byte[put];

put -= i;
AudioData.Position -= put;
put = AudioData.Read(temp, 0, put);
AudioData.Position -= put;

if (put > 0)
{
if (ReversePlayback)
for (int e = 0; e < put / frameSize; e++)
{
int frameSize = SrcChannels * 4;
byte[] temp = new byte[put];

AudioData.Position -= put;
put = AudioData.Read(temp, 0, put);
AudioData.Position -= put;

for (int e = 0; e < put / frameSize; e++)
{
Buffer.BlockCopy(temp, put - frameSize * (e + 1), data, frameSize * e, frameSize);
}
}
else
{
put = AudioData.Read(data, i, put);
Buffer.BlockCopy(temp, put - frameSize * (e + 1), data, frameSize * e, frameSize);
}

i += put;
}
else
{
put = AudioData.Read(data, i, put);
}

i += put;
}

if (ReversePlayback ? StreamPosition <= 0 : StreamPosition >= audioLen && !isLoading)
if (ReversePlayback ? AudioData.Position <= 0 : AudioData.Position >= AudioData.Length && !isLoading)
done = true;

if (underrun)
Expand All @@ -234,14 +174,22 @@ public virtual void Reset(bool resetPosition = true)
if (resetPosition)
{
SaveSeek = 0;
StreamPosition = 0;

if (AudioData != null)
AudioData.Position = 0;
}
}

/// <summary>
/// Returns current position converted into milliseconds.
/// </summary>
public virtual double GetCurrentTime() => !ReversePlayback ? GetMsFromBytes(StreamPosition) - GetResampleLatency() : GetMsFromBytes(StreamPosition) + GetResampleLatency();
public virtual double GetCurrentTime()
{
if (AudioData == null)
return 0;

return !ReversePlayback ? GetMsFromBytes(AudioData.Position) - GetResampleLatency() : GetMsFromBytes(AudioData.Position) + GetResampleLatency();
}

protected long SaveSeek;

Expand All @@ -255,14 +203,17 @@ public virtual void Seek(double seek)
{
long tmp = GetBytesFromMs(seek);

if (tmp < 0)
tmp = 0;

if (!isLoaded && tmp > AudioDataLength)
{
SaveSeek = tmp;
}
else if (AudioData != null && tmp <= AudioDataLength)
{
SaveSeek = 0;
StreamPosition = tmp;
AudioData.Position = tmp;
}
}

Expand Down

0 comments on commit a47afbd

Please sign in to comment.