@@ -1855,6 +1855,85 @@ TEST_F(AutoDJProcessorTest, FadeToDeck2_SeekBeforeTransition) {
18551855 EXPECT_DOUBLE_EQ (0 , deck2.playposition .get ());
18561856}
18571857
1858+ // Verify that the toDeck is started ~1 second before the fade threshold so it
1859+ // is already spinning when the crossfader begins to move, eliminating the
1860+ // cold-start gap.
1861+ //
1862+ // With a 100-second track and 10-second transition time in FixedFullTrack mode:
1863+ // fadeBeginPos = 0.9 (90 s / 100 s)
1864+ // earlyPlayPos = 0.89 (fadeBeginPos - 1s/100s)
1865+ // earlyStartPos = -0.01 (startPos 0.0 - 1s/100s)
1866+ TEST_F (AutoDJProcessorTest, FadeToDeck2_EarlyPlay_PreRoll) {
1867+ pProcessor->setTransitionMode (AutoDJProcessor::TransitionMode::FixedFullTrack);
1868+
1869+ TrackId testId = addTrackToCollection (kTrackLocationTest );
1870+ ASSERT_TRUE (testId.isValid ());
1871+
1872+ // Crossfader starts on the left.
1873+ mixer.crossfader .set (-1.0 );
1874+ // Use a 100-second track so positions are simple round numbers.
1875+ TrackPointer pTrack = newTestTrack ();
1876+ pTrack->setDuration (100 );
1877+ deck1.slotLoadTrack (pTrack,
1878+ #ifdef __STEM__
1879+ mixxx::StemChannelSelection (),
1880+ #endif
1881+ true );
1882+ deck1.fakeTrackLoadedEvent (pTrack);
1883+
1884+ PlaylistTableModel* pAutoDJTableModel = pProcessor->getTableModel ();
1885+ pAutoDJTableModel->appendTrack (testId);
1886+
1887+ EXPECT_CALL (*pProcessor, emitAutoDJStateChanged (AutoDJProcessor::ADJ_IDLE ));
1888+ EXPECT_CALL (*pProcessor, emitLoadTrackToPlayer (_, QString (" [Channel2]" ), false ));
1889+
1890+ AutoDJProcessor::AutoDJError err = pProcessor->toggleAutoDJ (true );
1891+ EXPECT_EQ (AutoDJProcessor::ADJ_OK , err);
1892+ EXPECT_EQ (AutoDJProcessor::ADJ_IDLE , pProcessor->getState ());
1893+
1894+ // Pretend the track load succeeds; deck2 is cued to startPos = 0.0.
1895+ deck2.slotLoadTrack (pTrack,
1896+ #ifdef __STEM__
1897+ mixxx::StemChannelSelection (),
1898+ #endif
1899+ false );
1900+ deck2.fakeTrackLoadedEvent (pTrack);
1901+
1902+ EXPECT_DOUBLE_EQ (0.0 , deck2.playposition .get ());
1903+ EXPECT_DOUBLE_EQ (0.0 , deck2.play .get ());
1904+ EXPECT_EQ (AutoDJProcessor::ADJ_IDLE , pProcessor->getState ());
1905+ EXPECT_DOUBLE_EQ (-1.0 , mixer.crossfader .get ());
1906+ EXPECT_DOUBLE_EQ (1.0 , deck1.play .get ());
1907+
1908+ // Seek deck1 to just before the early-play window (< 0.89). Deck2 should
1909+ // not start playing yet.
1910+ deck1.playposition .set (0.88 );
1911+ EXPECT_DOUBLE_EQ (0.0 , deck2.play .get ());
1912+ EXPECT_EQ (AutoDJProcessor::ADJ_IDLE , pProcessor->getState ());
1913+
1914+ // Seek deck1 to the early-play trigger point (fadeBeginPos - 1s = 0.89).
1915+ // Deck2 should now be playing and seeked 1 second before its startPos,
1916+ // i.e. at -0.01. State remains IDLE – the crossfader has not moved yet.
1917+ deck1.playposition .set (0.89 );
1918+ EXPECT_DOUBLE_EQ (1.0 , deck2.play .get ());
1919+ EXPECT_NEAR (-0.01 , deck2.playposition .get (), 1e-9 );
1920+ EXPECT_EQ (AutoDJProcessor::ADJ_IDLE , pProcessor->getState ());
1921+ EXPECT_DOUBLE_EQ (-1.0 , mixer.crossfader .get ());
1922+
1923+ // Advance deck1 to fadeBeginPos (0.9). The transition starts; deck2 was
1924+ // already playing so no redundant play() call is made.
1925+ EXPECT_CALL (*pProcessor, emitAutoDJStateChanged (AutoDJProcessor::ADJ_LEFT_FADING ));
1926+ deck1.playposition .set (0.9 );
1927+ EXPECT_EQ (AutoDJProcessor::ADJ_LEFT_FADING , pProcessor->getState ());
1928+ EXPECT_DOUBLE_EQ (1.0 , deck1.play .get ());
1929+ EXPECT_DOUBLE_EQ (1.0 , deck2.play .get ());
1930+
1931+ // Advance deck1 further into the fade; crossfader should have moved toward
1932+ // the right.
1933+ deck1.playposition .set (0.95 );
1934+ EXPECT_LT (-1.0 , mixer.crossfader .get ());
1935+ }
1936+
18581937TEST_F (AutoDJProcessorTest, TrackZeroLength) {
18591938 TrackId testId = addTrackToCollection (kTrackLocationTest );
18601939 ASSERT_TRUE (testId.isValid ());
0 commit comments