decoder/Bridge: truncate last chunk at the exact end_time
Instead of passing whole chunks to the MusicPipe and checking the end_time after each chunk, truncate the last chunk if it would exceed the end_time. This requires keeping track of the absolute PCM frame number. This fixes a problem with gapless CUE song transitions: a small part of the following song was always played twice. Closes #113
This commit is contained in:
parent
c43ea74b30
commit
986ec877b0
1
NEWS
1
NEWS
|
@ -1,4 +1,5 @@
|
|||
ver 0.20.18 (not yet released)
|
||||
* fix gapless CUE song transitions
|
||||
|
||||
ver 0.20.17 (2018/02/11)
|
||||
* output
|
||||
|
|
|
@ -300,6 +300,7 @@ DecoderBridge::CommandFinished()
|
|||
|
||||
initial_seek_running = false;
|
||||
timestamp = dc.start_time.ToDoubleS();
|
||||
absolute_frame = dc.start_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -319,6 +320,7 @@ DecoderBridge::CommandFinished()
|
|||
convert->Reset();
|
||||
|
||||
timestamp = dc.seek_time.ToDoubleS();
|
||||
absolute_frame = dc.seek_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
|
||||
}
|
||||
|
||||
dc.command = DecoderCommand::NONE;
|
||||
|
@ -427,6 +429,7 @@ DecoderBridge::SubmitTimestamp(double t)
|
|||
assert(t >= 0);
|
||||
|
||||
timestamp = t;
|
||||
absolute_frame = uint64_t(t * dc.in_audio_format.sample_rate);
|
||||
}
|
||||
|
||||
DecoderCommand
|
||||
|
@ -464,6 +467,29 @@ DecoderBridge::SubmitData(InputStream *is,
|
|||
return cmd;
|
||||
}
|
||||
|
||||
cmd = DecoderCommand::NONE;
|
||||
|
||||
const size_t frame_size = dc.in_audio_format.GetFrameSize();
|
||||
size_t data_frames = length / frame_size;
|
||||
|
||||
if (dc.end_time.IsPositive()) {
|
||||
/* enforce the given end time */
|
||||
|
||||
const uint64_t end_frame =
|
||||
dc.end_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
|
||||
if (absolute_frame >= end_frame)
|
||||
return DecoderCommand::STOP;
|
||||
|
||||
const uint64_t remaining_frames = end_frame - absolute_frame;
|
||||
if (data_frames >= remaining_frames) {
|
||||
/* past the end of the range: truncate this
|
||||
data submission and stop the decoder */
|
||||
data_frames = remaining_frames;
|
||||
length = data_frames * frame_size;
|
||||
cmd = DecoderCommand::STOP;
|
||||
}
|
||||
}
|
||||
|
||||
if (convert != nullptr) {
|
||||
assert(dc.in_audio_format != dc.out_audio_format);
|
||||
|
||||
|
@ -521,15 +547,11 @@ DecoderBridge::SubmitData(InputStream *is,
|
|||
|
||||
timestamp += (double)nbytes /
|
||||
dc.out_audio_format.GetTimeToSize();
|
||||
|
||||
if (dc.end_time.IsPositive() &&
|
||||
timestamp >= dc.end_time.ToDoubleS())
|
||||
/* the end of this range has been reached:
|
||||
stop decoding */
|
||||
return DecoderCommand::STOP;
|
||||
}
|
||||
|
||||
return DecoderCommand::NONE;
|
||||
absolute_frame += data_frames;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
DecoderCommand
|
||||
|
|
|
@ -49,6 +49,11 @@ public:
|
|||
*/
|
||||
double timestamp = 0;
|
||||
|
||||
/**
|
||||
* The time stamp of the next data chunk, in PCM frames.
|
||||
*/
|
||||
uint64_t absolute_frame = 0;
|
||||
|
||||
/**
|
||||
* Is the initial seek (to the start position of the sub-song)
|
||||
* pending, or has it been performed already?
|
||||
|
|
Loading…
Reference in New Issue