···16{
17 public sealed class TrackBass : Track, IBassAudio, IHasPitchAdjust
18 {
0019 private AsyncBufferStream dataStream;
2021 /// <summary>
···39 private bool isPlayed;
4041 private long byteLength;
000004243 private FileCallbacks fileCallbacks;
44 private SyncCallback stopCallback;
···96 if (success)
97 {
98 Length = seconds * 1000;
00099100 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);
232233 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;
2223 /// <summary>
···41 private bool isPlayed;
4243 private long byteLength;
44+45+ /// <summary>
46+ /// The last position that a seek will succeed for.
47+ /// </summary>
48+ private double lastSeekablePosition;
4950 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;
109110 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);
242243 await EnqueueAction(() =>
+3-5
osu.Framework/Audio/Track/Waveform.cs
···28 /// </summary>
29 private const int points_per_iteration = 100000;
3031- 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);
9596- int bytesPerPoint = samplesPerPoint * bytes_per_sample;
9798 points.Capacity = (int)(length / bytesPerPoint);
99100 // Each iteration pulls in several samples
101 int bytesPerIteration = bytesPerPoint * points_per_iteration;
102- var sampleBuffer = new float[bytesPerIteration / bytes_per_sample];
103104 // Read sample data
105 while (length > 0)
106 {
107 length = Bass.ChannelGetData(decodeStream, sampleBuffer, bytesPerIteration);
108- int samplesRead = (int)(length / bytes_per_sample);
109110 // 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;
300031 /// <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);
9394+ int bytesPerPoint = samplesPerPoint * TrackBass.BYTES_PER_SAMPLE;
9596 points.Capacity = (int)(length / bytesPerPoint);
9798 // Each iteration pulls in several samples
99 int bytesPerIteration = bytesPerPoint * points_per_iteration;
100+ var sampleBuffer = new float[bytesPerIteration / TrackBass.BYTES_PER_SAMPLE];
101102 // Read sample data
103 while (length > 0)
104 {
105 length = Bass.ChannelGetData(decodeStream, sampleBuffer, bytesPerIteration);
106+ int samplesRead = (int)(length / TrackBass.BYTES_PER_SAMPLE);
107108 // Each point is composed of multiple samples
109 for (int i = 0; i < samplesRead; i += samplesPerPoint)