A game framework written with osu! in mind.

Return false if attempting to seek to end in TrackBass (#2499)

Return false if attempting to seek to end in TrackBass

authored by

Dean Herbert and committed by
GitHub
3a5da84d 633abe34

+18 -7
+4 -1
osu.Framework.Tests/Audio/TrackBassTest.cs
··· 109 [Test] 110 public void TestSeekToEndFails() 111 { 112 - track.SeekAsync(track.Length); 113 updateTrack(); 114 115 Assert.AreEqual(0, track.CurrentTime); 116 } 117 118 [Test]
··· 109 [Test] 110 public void TestSeekToEndFails() 111 { 112 + bool? success = null; 113 + 114 + runOnAudioThread(() => { success = track.Seek(track.Length); }); 115 updateTrack(); 116 117 Assert.AreEqual(0, track.CurrentTime); 118 + Assert.IsFalse(success); 119 } 120 121 [Test]
+11 -1
osu.Framework/Audio/Track/TrackBass.cs
··· 16 { 17 public sealed class TrackBass : Track, IBassAudio, IHasPitchAdjust 18 { 19 private AsyncBufferStream dataStream; 20 21 /// <summary> ··· 39 private bool isPlayed; 40 41 private long byteLength; 42 43 private FileCallbacks fileCallbacks; 44 private SyncCallback stopCallback; ··· 96 if (success) 97 { 98 Length = seconds * 1000; 99 100 Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Frequency, out float frequency); 101 initialFrequency = frequency; ··· 227 { 228 // At this point the track may not yet be loaded which is indicated by a 0 length. 229 // In that case we still want to return true, hence the conservative length. 230 - double conservativeLength = Length == 0 ? double.MaxValue : Length; 231 double conservativeClamped = MathHelper.Clamp(seek, 0, conservativeLength); 232 233 await EnqueueAction(() =>
··· 16 { 17 public sealed class TrackBass : Track, IBassAudio, IHasPitchAdjust 18 { 19 + public const int BYTES_PER_SAMPLE = 4; 20 + 21 private AsyncBufferStream dataStream; 22 23 /// <summary> ··· 41 private bool isPlayed; 42 43 private long byteLength; 44 + 45 + /// <summary> 46 + /// The last position that a seek will succeed for. 47 + /// </summary> 48 + private double lastSeekablePosition; 49 50 private FileCallbacks fileCallbacks; 51 private SyncCallback stopCallback; ··· 103 if (success) 104 { 105 Length = seconds * 1000; 106 + 107 + // Bass does not allow seeking to the end of the track, so the last available position is 1 sample before. 108 + lastSeekablePosition = Bass.ChannelBytes2Seconds(activeStream, byteLength - BYTES_PER_SAMPLE) * 1000; 109 110 Bass.ChannelGetAttribute(activeStream, ChannelAttribute.Frequency, out float frequency); 111 initialFrequency = frequency; ··· 237 { 238 // At this point the track may not yet be loaded which is indicated by a 0 length. 239 // In that case we still want to return true, hence the conservative length. 240 + double conservativeLength = Length == 0 ? double.MaxValue : lastSeekablePosition; 241 double conservativeClamped = MathHelper.Clamp(seek, 0, conservativeLength); 242 243 await EnqueueAction(() =>
+3 -5
osu.Framework/Audio/Track/Waveform.cs
··· 28 /// </summary> 29 private const int points_per_iteration = 100000; 30 31 - private const int bytes_per_sample = 4; 32 - 33 /// <summary> 34 /// FFT1024 gives ~40hz accuracy. 35 /// </summary> ··· 93 // Each "point" is generated from a number of samples, each sample contains a number of channels 94 int samplesPerPoint = (int)(info.Frequency * resolution * info.Channels); 95 96 - int bytesPerPoint = samplesPerPoint * bytes_per_sample; 97 98 points.Capacity = (int)(length / bytesPerPoint); 99 100 // Each iteration pulls in several samples 101 int bytesPerIteration = bytesPerPoint * points_per_iteration; 102 - var sampleBuffer = new float[bytesPerIteration / bytes_per_sample]; 103 104 // Read sample data 105 while (length > 0) 106 { 107 length = Bass.ChannelGetData(decodeStream, sampleBuffer, bytesPerIteration); 108 - int samplesRead = (int)(length / bytes_per_sample); 109 110 // Each point is composed of multiple samples 111 for (int i = 0; i < samplesRead; i += samplesPerPoint)
··· 28 /// </summary> 29 private const int points_per_iteration = 100000; 30 31 /// <summary> 32 /// FFT1024 gives ~40hz accuracy. 33 /// </summary> ··· 91 // Each "point" is generated from a number of samples, each sample contains a number of channels 92 int samplesPerPoint = (int)(info.Frequency * resolution * info.Channels); 93 94 + int bytesPerPoint = samplesPerPoint * TrackBass.BYTES_PER_SAMPLE; 95 96 points.Capacity = (int)(length / bytesPerPoint); 97 98 // Each iteration pulls in several samples 99 int bytesPerIteration = bytesPerPoint * points_per_iteration; 100 + var sampleBuffer = new float[bytesPerIteration / TrackBass.BYTES_PER_SAMPLE]; 101 102 // Read sample data 103 while (length > 0) 104 { 105 length = Bass.ChannelGetData(decodeStream, sampleBuffer, bytesPerIteration); 106 + int samplesRead = (int)(length / TrackBass.BYTES_PER_SAMPLE); 107 108 // Each point is composed of multiple samples 109 for (int i = 0; i < samplesRead; i += samplesPerPoint)