-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
repeat: after last track sample, fill buffer with samples from track start #11532
Conversation
@mevsme please give this a shot with your test tracks. |
ee86412
to
b92320d
Compare
b92320d
to
1102067
Compare
The ReverseTest failed, though only on Windows. In a previous run (before I pushed a comment update) all tests on all OS passed.
|
I could reproduce the issue and also confirm the fix 🎉 Steps tp reproduce:
|
1102067
to
8c791de
Compare
8c791de
to
c32074c
Compare
Unfortunately this fix breaks quantization for repeating tracks. (which is at least consistent with beatloops != n beats, as in 2.3) |
I fixed this. Though I wonder whether quantization for repeat is a) actually desired / expected, or if b) this was just an implicit side effect of the previous repeat implementation. if (repeat_enabled) {
double fractionalPos = at_start ? 1.0 : 0;
doSeekFractional(fractionalPos, SEEK_STANDARD); <--- triggers phase sync
} else { I suspect it's b), at least the quantize description doesn't mention it (though it doesn't mention other aspects either, e.g. phase sync of quantized decks). Anyway, now the behaviour is exactly as before + the audio gap fix. It would be nice to also address the TODO (that also applies to the previous implementation, and when scratching is stopped and tracks are resync'ed): currently there is one unsyced buffer played before tracks are quantized. if (m_pRepeat->toBool() && m_pQuantize->toBool() &&
(m_filepos_play > playpos_old) == backwards) {
// TODO() The resulting seek is processed in the following callback
// That is to late
requestSyncPhase();
} |
c32074c
to
82d7cbd
Compare
or with samples from end, if playing in reverse. Previously, the last buffer at track end was padded with silence which makes the track longer than it actually is, then seeked to track start. With loop tracks (length is exactly n beats) this caused beat offsets.
82d7cbd
to
7c55f3e
Compare
(m_filepos_play > playpos_old) == backwards) { | ||
// TODO() The resulting seek is processed in the following callback | ||
// That is to late | ||
requestSyncPhase(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
requestSyncPhase() requires an other track playing to be in sync. Did you consider a solution where the repeat + quantize becomes a beat loop that the track stays in sync with itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, this is only supposed to sync phase when there's another track. I'm still not sure if that's a good idea, and for which use case it helps, considering users expecting beat and phase sync would set the loop manually, i.e. don't rely on phase sync to snap to the correct beat.
and no, this should not be an extension of the original beat loop fix.
This looks already like a good improvement. Is it a lat minute 2.3.5 candidate? |
I have created a 1 s 440 Hz wav track and play it in repeat from the lead in. In audacity it has full power from start to end. In this PR the track starts with click sound (no ramping in). The original code shows a gap in the first iteration. Is this a caching issue? Later it kind of works, but we see ramping in and out. What is the desired solution? We also have the issue that we cannot play life recordings gap-less. This would require a start to end transition without overlapping and fading. This is different if we consider Quantize. I think we can expect that with quantize enabled the track plays beat matches with itself. In this case crass-fading is desired. Mmm, I am afraid we need to go back to the cutting table. I like the idea of using the looping code. It has already the cross fade feature. If we use the silence after the track and before the track for cross-fading, it will have no addible effect and the back-to-back mode without cross fading works implicit. |
This could be for 2.3.5 but it has no prio IMO, given the issue seems to exist very long already, it's only one older report and not much interest otherwise. |
The sine wave file has no ramping and no silence itself, right? If yes, could try with a loop from track start and track end, both 2.3 and this PR, and post a screenshot, too? I have a local experimental commit that does the quatization (for repeat) already in LoopingControl and it unveiled an play pos logging issue in ReadAheadManager that would somehow revert the applied quantization. So yes, even though this is an improvement there's more to be done to have proper gapless playback. |
Here's my comparison of 2.3 / PR with a 2s 440 Hz sine wave I have no explanation for the alternating fading time, though I didn't yet look into the reader at all where the cross-fading seems to be done. Maybe it's beause of the mismatch buffer size vs. available samples (original silence issue). If so, with a sine wave with exactly [n * buffer length] we should see identical crossfades. I'd say this is good to go because at least the repeat behaviour is now consistent with the (full-track) loop behaviour. |
I can reproduce the same behavior with a shorter loop starting at the beginning. My assumption form a above is wrong that looping already allows gapless playback, because it uses for crossfading the last samples in a loop and the same amount of samples in front of the loop. Unfortunately the manual set out cue is randomly shifted after the track: This is due to the quantitation effect of the engine buffer. It plays a bit beyond the track to be able to fill a very last buffer with the remaining samples form the track. The rest is padded with silence. The loop out is here placed at the end of the silence at a place that may not reached if less padding is required on the next loop iteration. This seems to be a slightly related bug that is also happening in 2.4. The window for last minute 2.3.5 merges is closed now and we are waiting for smoke test: |
ronso0#42 fixes the issue with cross-fading. |
…rossfading loop-end into loop-in. This avoids a clicking noise with loops near the track start or end.
… during the engine call.
Thank you! I picked those commits and removed the debug output. |
With quantize enabled, a (visual) issue remains: when a track wraps around to the start, the visual position is in the preroll briefly before catching up to a qunatized position, though the recording (sine wave) shows continuous playback 🤷♂️ |
How can this be reproduced? Does it also affect the track time display? |
I played the testing sine wave (2s) and a longer track. Both with repeat and quantize enabled. |
Seems to be a waveform issue only (on both decks btw), the palypos label is always in the positive range (I don't see a - when the playhead is in the preroll). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Oh I noticed this code was there, but got lost: |
or with samples from end if playing in reverse.
This enables gapless playback when
repeat
is enabled.Previously, the last buffer at track end was padded with silence which makes the track longer than it actually is. With loop tracks (length is exactly n beats) this causes beat offsets with BPM-sync'ed tracks (non-quantized).
Quantize would fix the offset but the audio gap remains AFAICT.
See #9842 and https://mixxx.zulipchat.com/#narrow/stream/109171-development/topic/repeat.20accuracy
NOTE This is just a minimal invasive POC hack that abuses LoopingControl::nextTrigger because
Maybe there is a better place or a separate function is required.
Also some cleanup needs to be done in
EngineBuffer::processTrackLocked
, there are residues.Probably related: #11381
Closes #9842