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)
|
ver 0.20.18 (not yet released)
|
||||||
|
* fix gapless CUE song transitions
|
||||||
|
|
||||||
ver 0.20.17 (2018/02/11)
|
ver 0.20.17 (2018/02/11)
|
||||||
* output
|
* output
|
||||||
|
@ -300,6 +300,7 @@ DecoderBridge::CommandFinished()
|
|||||||
|
|
||||||
initial_seek_running = false;
|
initial_seek_running = false;
|
||||||
timestamp = dc.start_time.ToDoubleS();
|
timestamp = dc.start_time.ToDoubleS();
|
||||||
|
absolute_frame = dc.start_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -319,6 +320,7 @@ DecoderBridge::CommandFinished()
|
|||||||
convert->Reset();
|
convert->Reset();
|
||||||
|
|
||||||
timestamp = dc.seek_time.ToDoubleS();
|
timestamp = dc.seek_time.ToDoubleS();
|
||||||
|
absolute_frame = dc.seek_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
dc.command = DecoderCommand::NONE;
|
dc.command = DecoderCommand::NONE;
|
||||||
@ -427,6 +429,7 @@ DecoderBridge::SubmitTimestamp(double t)
|
|||||||
assert(t >= 0);
|
assert(t >= 0);
|
||||||
|
|
||||||
timestamp = t;
|
timestamp = t;
|
||||||
|
absolute_frame = uint64_t(t * dc.in_audio_format.sample_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
DecoderCommand
|
DecoderCommand
|
||||||
@ -464,6 +467,29 @@ DecoderBridge::SubmitData(InputStream *is,
|
|||||||
return cmd;
|
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) {
|
if (convert != nullptr) {
|
||||||
assert(dc.in_audio_format != dc.out_audio_format);
|
assert(dc.in_audio_format != dc.out_audio_format);
|
||||||
|
|
||||||
@ -521,15 +547,11 @@ DecoderBridge::SubmitData(InputStream *is,
|
|||||||
|
|
||||||
timestamp += (double)nbytes /
|
timestamp += (double)nbytes /
|
||||||
dc.out_audio_format.GetTimeToSize();
|
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
|
DecoderCommand
|
||||||
|
@ -49,6 +49,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
double timestamp = 0;
|
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)
|
* Is the initial seek (to the start position of the sub-song)
|
||||||
* pending, or has it been performed already?
|
* pending, or has it been performed already?
|
||||||
|
Loading…
Reference in New Issue
Block a user