47 auto pCoreActionController = pHydrogen->getCoreActionController();
48 auto pAE = pHydrogen->getAudioEngine();
50 pCoreActionController->activateTimeline(
true );
51 pCoreActionController->addTempoMarker( 0, 120 );
52 pCoreActionController->addTempoMarker( 3, 100 );
53 pCoreActionController->addTempoMarker( 5, 40 );
54 pCoreActionController->addTempoMarker( 7, 200 );
56 auto checkFrame = [](
long long nFrame,
double fTolerance ) {
60 const long long nFrameCheck =
63 if ( nFrameCheck != nFrame || std::abs( fTickMismatch ) > fTolerance ) {
65 QString(
"[testFrameToTickConversion::checkFrame] nFrame: %1, fTick: %2, nFrameComputed: %3, fTickMismatch: %4, frame diff: %5, fTolerance: %6" )
66 .arg( nFrame ).arg( fTick, 0,
'E', -1 ).arg( nFrameCheck )
67 .arg( fTickMismatch, 0,
'E', -1 ).arg( nFrameCheck - nFrame )
68 .arg( fTolerance, 0,
'E', -1 ) );
71 checkFrame( 342732, 1e-10 );
72 checkFrame( 1037223, 1e-10 );
73 checkFrame( 453610333722, 1e-6 );
75 auto checkTick = [](
double fTick,
double fTolerance ) {
77 const long long nFrame =
80 const double fTickCheck =
83 if ( abs( fTickCheck - fTick ) > fTolerance ) {
85 QString(
"[testFrameToTickConversion::checkTick] nFrame: %1, fTick: %2, fTickComputed: %3, fTickMismatch: %4, tick diff: %5, fTolerance: %6" )
86 .arg( nFrame ).arg( fTick, 0,
'E', -1 ).arg( fTickCheck, 0,
'E', -1 )
87 .arg( fTickMismatch, 0,
'E', -1 ).arg( fTickCheck - fTick, 0,
'E', -1 )
88 .arg( fTolerance, 0,
'E', -1 ));
91 checkTick( 552, 1e-9 );
92 checkTick( 1939, 1e-9 );
93 checkTick( 534623409, 1e-6 );
94 checkTick( pAE->m_fSongSizeInTicks * 3, 1e-9 );
99 auto pSong = pHydrogen->getSong();
101 auto pCoreActionController = pHydrogen->getCoreActionController();
102 auto pAE = pHydrogen->getAudioEngine();
103 auto pTransportPos = pAE->getTransportPosition();
104 auto pQueuingPos = pAE->m_pQueuingPosition;
106 pCoreActionController->activateTimeline(
false );
107 pCoreActionController->activateLoopMode(
true );
112 std::random_device randomSeed;
113 std::default_random_engine randomEngine( randomSeed() );
114 std::uniform_int_distribution<int> frameDist( 1, pPref->m_nBufferSize );
115 std::uniform_real_distribution<float> tempoDist(
MIN_BPM,
MAX_BPM );
120 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
126 double fCheckTick, fLastTickIntervalEnd;
127 long long nCheckFrame, nLastTransportFrame, nTotalFrames, nLastLookahead;
128 long nLastQueuingTick;
131 auto resetVariables = [&]() {
132 nLastTransportFrame = 0;
133 nLastQueuingTick = 0;
134 fLastTickIntervalEnd = 0;
141 const int nMaxCycles =
142 std::max( std::ceil(
static_cast<double>(pAE->m_fSongSizeInTicks) /
143 static_cast<double>(pPref->m_nBufferSize) *
144 static_cast<double>(pTransportPos->getTickSize()) * 4.0 ),
145 static_cast<double>(pAE->m_fSongSizeInTicks) );
147 while ( pTransportPos->getDoubleTick() <
148 pAE->getSongSizeInTicks() ) {
149 nFrames = frameDist( randomEngine );
151 "testTransportProcessing : song mode : constant tempo", nFrames,
152 &nLastLookahead, &nLastTransportFrame, &nTotalFrames,
153 &nLastQueuingTick, &fLastTickIntervalEnd,
true );
156 if ( nn > nMaxCycles ) {
158 QString(
"[testTransportProcessing] [song mode : constant tempo] end of the song wasn't reached in time. pTransportPos->getFrame(): %1, pTransportPos->getDoubleTick(): %2, pTransportPos->getTickSize(): %3, pAE->getSongSizeInTicks(): %4, nMaxCycles: %5" )
159 .arg( pTransportPos->getFrame() )
160 .arg( pTransportPos->getDoubleTick(), 0,
'f' )
161 .arg( pTransportPos->getTickSize(), 0,
'f' )
162 .arg( pAE->getSongSizeInTicks(), 0,
'f' )
163 .arg( nMaxCycles ) );
168 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
175 pCoreActionController->activateLoopMode(
false );
180 while ( nn <= nMaxCycles ) {
181 nFrames = frameDist( randomEngine );
182 pAE->incrementTransportPosition( nFrames );
184 if ( pAE->isEndOfSongReached( pAE->m_pTransportPosition ) ) {
186 if ( pTransportPos->getTick() < pAE->getSongSizeInTicks() ) {
188 QString(
"[testTransportProcessing] [song mode : no looping] final tick was not reached at song end. pTransportPos->getTick: [%1], pAE->getSongSizeInTicks: %2" )
189 .arg( pTransportPos->getTick() ).arg( pAE->getSongSizeInTicks() ) );
195 if ( nn > nMaxCycles ) {
197 QString(
"[testTransportProcessing] [song mode : no looping] end of the song wasn't reached in time. pTransportPos->getFrame(): %1, pTransportPos->getDoubleTick(): %2, pTransportPos->getTickSize(): %3, pAE->getSongSizeInTicks(): %4, nMaxCycles: %5" )
198 .arg( pTransportPos->getFrame() )
199 .arg( pTransportPos->getDoubleTick(), 0,
'f' )
200 .arg( pTransportPos->getTickSize(), 0,
'f' )
201 .arg( pAE->getSongSizeInTicks(), 0,
'f' )
202 .arg( nMaxCycles ) );
207 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
214 pCoreActionController->activateLoopMode(
true );
222 float fLastBpm = pTransportPos->getBpm();
224 const int nCyclesPerTempo = 11;
225 while ( pTransportPos->getDoubleTick() <
226 pAE->getSongSizeInTicks() ) {
228 fBpm = tempoDist( randomEngine );
229 pAE->setNextBpm( fBpm );
230 pAE->updateBpmAndTickSize( pTransportPos );
231 pAE->updateBpmAndTickSize( pQueuingPos );
235 for (
int cc = 0; cc < nCyclesPerTempo; ++cc ) {
236 nFrames = frameDist( randomEngine );
238 QString(
"testTransportProcessing : song mode : variable tempo %1->%2" )
239 .arg( fLastBpm, 0,
'f' ).arg( fBpm, 0,
'f' ), nFrames, &nLastLookahead,
240 &nLastTransportFrame, &nTotalFrames, &nLastQueuingTick,
241 &fLastTickIntervalEnd,
true );
247 if ( nn > nMaxCycles ) {
249 "[testTransportProcessing] [song mode : variable tempo] end of the song wasn't reached in time." );
257 pCoreActionController->activateSongMode(
false );
264 fLastBpm = pTransportPos->getBpm();
266 const int nDifferentTempos = 10;
267 for (
int tt = 0; tt < nDifferentTempos; ++tt ) {
269 fBpm = tempoDist( randomEngine );
271 pAE->setNextBpm( fBpm );
272 pAE->updateBpmAndTickSize( pTransportPos );
273 pAE->updateBpmAndTickSize( pQueuingPos );
277 for (
int cc = 0; cc < nCyclesPerTempo; ++cc ) {
278 nFrames = frameDist( randomEngine );
280 QString(
"testTransportProcessing : pattern mode : variable tempo %1->%2" )
281 .arg( fLastBpm ).arg( fBpm ), nFrames, &nLastLookahead,
282 &nLastTransportFrame, &nTotalFrames, &nLastQueuingTick,
283 &fLastTickIntervalEnd,
true );
291 pCoreActionController->activateSongMode(
true );
296 auto pSong = pHydrogen->getSong();
297 auto pTimeline = pHydrogen->getTimeline();
299 auto pCoreActionController = pHydrogen->getCoreActionController();
300 auto pAE = pHydrogen->getAudioEngine();
301 auto pTransportPos = pAE->getTransportPosition();
302 auto pQueuingPos = pAE->m_pQueuingPosition;
304 pCoreActionController->activateLoopMode(
true );
310 auto activateTimeline = [&](
bool bEnabled ) {
311 pPref->setUseTimelineBpm( bEnabled );
312 pSong->setIsTimelineActivated( bEnabled );
315 pTimeline->activate();
317 pTimeline->deactivate();
320 pAE->handleTimelineChange();
322 activateTimeline(
true );
324 std::random_device randomSeed;
325 std::default_random_engine randomEngine( randomSeed() );
326 std::uniform_int_distribution<int> frameDist( 1, pPref->m_nBufferSize );
327 std::uniform_real_distribution<float> tempoDist(
MIN_BPM,
MAX_BPM );
332 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
338 double fCheckTick, fLastTickIntervalEnd;
339 long long nCheckFrame, nLastTransportFrame, nTotalFrames, nLastLookahead;
340 long nLastQueuingTick;
343 auto resetVariables = [&]() {
344 nLastTransportFrame = 0;
345 nLastQueuingTick = 0;
346 fLastTickIntervalEnd = 0;
353 const int nMaxCycles =
354 std::max( std::ceil(
static_cast<double>(pAE->m_fSongSizeInTicks) /
355 static_cast<double>(pPref->m_nBufferSize) *
356 static_cast<double>(pTransportPos->getTickSize()) * 4.0 ),
357 static_cast<double>(pAE->m_fSongSizeInTicks) );
359 while ( pTransportPos->getDoubleTick() <
360 pAE->getSongSizeInTicks() ) {
361 nFrames = frameDist( randomEngine );
363 QString(
"[testTransportProcessingTimeline : song mode : all timeline]" ),
364 nFrames, &nLastLookahead, &nLastTransportFrame, &nTotalFrames,
365 &nLastQueuingTick, &fLastTickIntervalEnd,
false );
368 if ( nn > nMaxCycles ) {
370 QString(
"[testTransportProcessingTimeline] [all timeline] end of the song wasn't reached in time. pTransportPos->getFrame(): %1, pTransportPos->getDoubleTick(): %2, pTransportPos->getTickSize(): %3, pAE->getSongSizeInTicks(): %4, nMaxCycles: %5" )
371 .arg( pTransportPos->getFrame() )
372 .arg( pTransportPos->getDoubleTick(), 0,
'f' )
373 .arg( pTransportPos->getTickSize(), 0,
'f' )
374 .arg( pAE->getSongSizeInTicks(), 0,
'f' )
375 .arg( nMaxCycles ) );
383 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
387 float fLastBpm = pTransportPos->getBpm();
389 const int nCyclesPerTempo = 11;
390 while ( pTransportPos->getDoubleTick() <
391 pAE->getSongSizeInTicks() ) {
395 activateTimeline(
false );
396 fBpm = tempoDist( randomEngine );
397 pAE->setNextBpm( fBpm );
398 pAE->updateBpmAndTickSize( pTransportPos );
399 pAE->updateBpmAndTickSize( pQueuingPos );
401 sContext =
"no timeline";
404 activateTimeline(
true );
407 sContext =
"timeline";
410 for (
int cc = 0; cc < nCyclesPerTempo; ++cc ) {
411 nFrames = frameDist( randomEngine );
413 QString(
"testTransportProcessing : alternating timeline : bpm %1->%2 : %3" )
414 .arg( fLastBpm ).arg( fBpm ).arg( sContext ),
415 nFrames, &nLastLookahead, &nLastTransportFrame, &nTotalFrames,
416 &nLastQueuingTick, &fLastTickIntervalEnd,
false );
422 if ( nn > nMaxCycles ) {
424 "[testTransportProcessingTimeline] [alternating timeline] end of the song wasn't reached in time." );
434 auto pSong = pHydrogen->getSong();
436 auto pCoreActionController = pHydrogen->getCoreActionController();
437 auto pAE = pHydrogen->getAudioEngine();
438 auto pTransportPos = pAE->getTransportPosition();
440 pCoreActionController->activateLoopMode(
true );
441 pCoreActionController->activateSongMode(
true );
449 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
454 double fLastTickIntervalEnd;
455 long long nLastTransportFrame, nTotalFrames, nLastLookahead;
456 long nLastQueuingTick;
459 auto resetVariables = [&]() {
460 nLastTransportFrame = 0;
461 nLastQueuingTick = 0;
462 fLastTickIntervalEnd = 0;
469 const int nLoops = 3;
470 const double fSongSizeInTicks = pAE->m_fSongSizeInTicks;
472 const int nMaxCycles =
473 std::max( std::ceil( fSongSizeInTicks /
474 static_cast<double>(pPref->m_nBufferSize) *
475 static_cast<double>(pTransportPos->getTickSize()) * 4.0 ),
484 bool bLoopEnabled =
true;
486 while ( pTransportPos->getDoubleTick() <
487 fSongSizeInTicks * ( nLoops + 2 ) ) {
489 QString(
"[testTransportProcessingTimeline : song mode : all timeline]" ),
490 pPref->m_nBufferSize, &nLastLookahead, &nLastTransportFrame,
491 &nTotalFrames, &nLastQueuingTick, &fLastTickIntervalEnd,
false );
500 if ( bLoopEnabled && pTransportPos->getDoubleTick() >
501 fSongSizeInTicks * ( nLoops - 1 ) ) {
504 pCoreActionController->activateLoopMode(
false );
510 if ( nn > nMaxCycles ||
511 pTransportPos->getDoubleTick() > fSongSizeInTicks * nLoops ) {
513 QString(
"[testLoopMode] transport is rolling for too long. pTransportPos: %1,\n\tfSongSizeInTicks(): %2, nLoops: %3, pPref->m_nBufferSize: %4, nMaxCycles: %5" )
514 .arg( pTransportPos->toQString() )
515 .arg( fSongSizeInTicks, 0,
'f' ).arg( nLoops )
516 .arg( pPref->m_nBufferSize ).arg( nMaxCycles ) );
521 if ( pAE->m_pQueuingPosition->getDoubleTick() < fSongSizeInTicks * nLoops ) {
523 QString(
"[testLoopMode] transport ended prematurely. pAE->m_pQueuingPosition: %1,\n\tfSongSizeInTicks(): %2, nLoops: %3, pPref->m_nBufferSize: %4" )
524 .arg( pAE->m_pQueuingPosition->toQString() )
525 .arg( fSongSizeInTicks, 0,
'f' ).arg( nLoops )
526 .arg( pPref->m_nBufferSize ) );
536 long long* nLastLookahead,
537 long long* nLastTransportFrame,
538 long long* nTotalFrames,
539 long* nLastQueuingTick,
540 double* fLastTickIntervalEnd,
541 bool bCheckLookahead ) {
545 auto pQueuingPos = pAE->m_pQueuingPosition;
547 double fTickStart, fTickEnd;
548 const long long nLeadLag =
549 pAE->computeTickInterval( &fTickStart, &fTickEnd, nFrames );
550 fTickStart = pAE->coarseGrainTick( fTickStart );
551 fTickEnd = pAE->coarseGrainTick( fTickEnd );
553 if ( bCheckLookahead ) {
556 if ( *nLastLookahead != 0 &&
559 QString(
"[processTransport : lookahead] [%1] with one and the same BPM/tick size the lookahead must be consistent! [ %2 -> %3 ]" )
560 .arg( sContext ).arg( *nLastLookahead )
566 pAE->updateNoteQueue( nFrames );
567 pAE->incrementTransportPosition( nFrames );
569 if ( pAE->isEndOfSongReached( pAE->m_pTransportPosition ) ) {
576 pTransportPos,
"[processTransport] " + sContext );
579 pQueuingPos,
"[processTransport] " + sContext );
581 if ( pTransportPos->getFrame() - nFrames -
582 pTransportPos->getFrameOffsetTempo() != *nLastTransportFrame ) {
584 QString(
"[processTransport : transport] [%1] inconsistent frame update. pTransportPos->getFrame(): %2, nFrames: %3, nLastTransportFrame: %4, pTransportPos->getFrameOffsetTempo(): %5, pAE->m_fSongSizeInTicks: %6, pAE->m_nLoopsDone: %7" )
585 .arg( sContext ).arg( pTransportPos->getFrame() ).arg( nFrames )
586 .arg( *nLastTransportFrame ).arg( pTransportPos->getFrameOffsetTempo() )
587 .arg( pAE->m_fSongSizeInTicks ).arg( pAE->m_nLoopsDone ) );
589 *nLastTransportFrame = pTransportPos->getFrame() -
590 pTransportPos->getFrameOffsetTempo();
592 const int nNoteQueueUpdate =
593 static_cast<int>( fTickEnd ) -
static_cast<int>( fTickStart );
597 if ( *nLastQueuingTick > 0 && nNoteQueueUpdate > 0 ) {
598 if ( pQueuingPos->getTick() - nNoteQueueUpdate !=
600 ! pAE->isEndOfSongReached( pQueuingPos ) ) {
602 QString(
"[processTransport : queuing pos] [%1] inconsistent tick update. pQueuingPos->getTick(): %2, nNoteQueueUpdate: %3, nLastQueuingTick: %4, fTickStart: %5, fTickEnd: %6, nFrames = %7, pTransportPos: %8, pQueuingPos: %9, pAE->m_fSongSizeInTicks: %10, pAE->m_nLoopsDone: %11" )
603 .arg( sContext ).arg( pQueuingPos->getTick() )
604 .arg( nNoteQueueUpdate ).arg( *nLastQueuingTick )
605 .arg( fTickStart, 0,
'f' ).arg( fTickEnd, 0,
'f' )
606 .arg( nFrames ).arg( pTransportPos->toQString() )
607 .arg( pQueuingPos->toQString() )
608 .arg( pAE->m_fSongSizeInTicks ).arg( pAE->m_nLoopsDone ));
611 *nLastQueuingTick = pQueuingPos->getTick();
617 if ( std::abs( fTickStart - *fLastTickIntervalEnd ) > 1E-4 ||
618 fTickStart > fTickEnd ) {
620 QString(
"[processTransport : tick interval] [%1] inconsistent update. old: [ ... : %2 ], new: [ %3, %4 ], pTransportPos->getTickOffsetQueuing(): %5, diff: %6" )
621 .arg( sContext ).arg( *fLastTickIntervalEnd ).arg( fTickStart )
622 .arg( fTickEnd ).arg( pTransportPos->getTickOffsetQueuing() )
623 .arg( std::abs( fTickStart - *fLastTickIntervalEnd ), 0,
'E', -1 ) );
625 *fLastTickIntervalEnd = fTickEnd;
630 *nTotalFrames += nFrames;
631 if ( pTransportPos->getFrame() - pTransportPos->getFrameOffsetTempo() !=
634 QString(
"[processTransport : total] [%1] total frames incorrect. pTransportPos->getFrame(): %2, pTransportPos->getFrameOffsetTempo(): %3, nTotalFrames: %4" )
635 .arg( sContext ).arg( pTransportPos->getFrame() )
636 .arg( pTransportPos->getFrameOffsetTempo() ).arg( *nTotalFrames ) );
755 auto pSong = pHydrogen->getSong();
756 auto pCoreActionController = pHydrogen->getCoreActionController();
758 auto pAE = pHydrogen->getAudioEngine();
759 auto pTransportPos = pAE->getTransportPosition();
761 pCoreActionController->activateTimeline(
false );
762 pCoreActionController->activateLoopMode(
true );
767 const int nColumns = pSong->getPatternGroupVector()->size();
769 std::random_device randomSeed;
770 std::default_random_engine randomEngine( randomSeed() );
771 std::uniform_real_distribution<double> tickDist( 1, pPref->m_nBufferSize );
772 std::uniform_int_distribution<int> columnDist( nColumns, nColumns + 100 );
777 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
779 const uint32_t nFrames = 500;
780 const double fInitialSongSize = pAE->m_fSongSizeInTicks;
784 auto checkState = [&](
const QString& sContext,
bool bSongSizeShouldChange ){
787 QString(
"[testSongSizeChangeInLoopMode::checkState] [%1] before increment" )
790 if ( bSongSizeShouldChange &&
791 fInitialSongSize == pAE->m_fSongSizeInTicks ) {
793 QString(
"[testSongSizeChangeInLoopMode] [%1] song size stayed the same [%2->%3]")
794 .arg( sContext ).arg( fInitialSongSize ).arg( pAE->m_fSongSizeInTicks ) );
796 else if ( ! bSongSizeShouldChange &&
797 fInitialSongSize != pAE->m_fSongSizeInTicks ) {
799 QString(
"[testSongSizeChangeInLoopMode] [%1] unexpected song enlargement [%2->%3]")
800 .arg( sContext ).arg( fInitialSongSize ).arg( pAE->m_fSongSizeInTicks ) );
803 pAE->incrementTransportPosition( nFrames );
807 QString(
"[testSongSizeChangeInLoopMode::checkState] [%1] after increment" )
811 const int nNumberOfTogglings = 5;
812 for (
int nn = 0; nn < nNumberOfTogglings; ++nn ) {
814 fTick = tickDist( randomEngine );
815 pAE->locate( fInitialSongSize + fTick );
817 checkState( QString(
"relocation to [%1]" ).arg( fTick ),
false );
819 nNewColumn = columnDist( randomEngine );
823 pCoreActionController->toggleGridCell( nNewColumn, 0 );
827 checkState( QString(
"toggling column [%1]" ).arg( nNewColumn ),
true );
831 pCoreActionController->toggleGridCell( nNewColumn, 0 );
835 checkState( QString(
"again toggling column [%1]" ).arg( nNewColumn ),
false );
844 auto pSong = pHydrogen->getSong();
845 auto pCoreActionController = pHydrogen->getCoreActionController();
847 auto pAE = pHydrogen->getAudioEngine();
848 auto pSampler = pAE->getSampler();
849 auto pTransportPos = pAE->getTransportPosition();
850 auto pQueuingPos = pAE->m_pQueuingPosition;
852 pCoreActionController->activateTimeline(
false );
853 pCoreActionController->activateLoopMode(
false );
854 pCoreActionController->activateSongMode(
true );
858 std::random_device randomSeed;
859 std::default_random_engine randomEngine( randomSeed() );
860 std::uniform_int_distribution<int> frameDist( pPref->m_nBufferSize / 2,
861 pPref->m_nBufferSize );
866 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
875 std::max( std::ceil(
static_cast<double>(pAE->m_fSongSizeInTicks) /
876 static_cast<double>(pPref->m_nBufferSize) *
877 static_cast<double>(pTransportPos->getTickSize()) * 4.0 ),
878 static_cast<double>(pAE->m_fSongSizeInTicks) );
884 auto notesInSong = pSong->getAllNotes();
885 std::vector<std::shared_ptr<Note>> notesInSongQueue;
886 std::vector<std::shared_ptr<Note>> notesInSamplerQueue;
888 auto retrieveNotes = [&](
const QString& sContext ) {
892 pAE->processAudio( nFrames );
895 pSampler->getPlayingNotesQueue() );
897 pAE->incrementTransportPosition( nFrames );
900 if ( nn > nMaxCycles ) {
902 QString(
"[testNoteEnqueuing::retrieveNotes] [%1] end of the song wasn't reached in time. pTransportPos->getFrame(): %2, pTransportPos->getDoubleTick(): %3, getTickSize(): %4, pAE->m_fSongSizeInTicks: %5, nMaxCycles: %6" )
903 .arg( sContext ).arg( pTransportPos->getFrame() )
904 .arg( pTransportPos->getDoubleTick(), 0,
'f' )
905 .arg( pTransportPos->getTickSize(), 0,
'f' )
906 .arg( pAE->m_fSongSizeInTicks, 0,
'f' ).arg( nMaxCycles ) );
912 while ( pQueuingPos->getDoubleTick() < pAE->m_fSongSizeInTicks ) {
914 nFrames = frameDist( randomEngine );
915 pAE->updateNoteQueue( nFrames );
916 retrieveNotes(
"song mode" );
919 auto checkQueueConsistency = [&](
const QString& sContext ) {
920 if ( notesInSongQueue.size() !=
921 notesInSong.size() ) {
922 QString sMsg = QString(
"[testNoteEnqueuing::checkQueueConsistency] [%1] Mismatch between notes count in Song [%2] and NoteQueue [%3]. Song:\n" )
923 .arg( sContext ).arg( notesInSong.size() )
924 .arg( notesInSongQueue.size() );
925 for (
int ii = 0; ii < notesInSong.size(); ++ii ) {
926 auto note = notesInSong[ ii ];
927 sMsg.append( QString(
"\t[%1] instr: %2, position: %3, noteStart: %4, velocity: %5\n")
929 .arg( note->get_instrument()->get_name() )
930 .arg( note->get_position() )
931 .arg( note->getNoteStart() )
932 .arg( note->get_velocity() ) );
934 sMsg.append(
"NoteQueue:\n" );
935 for (
int ii = 0; ii < notesInSongQueue.size(); ++ii ) {
936 auto note = notesInSongQueue[ ii ];
937 sMsg.append( QString(
"\t[%1] instr: %2, position: %3, noteStart: %4, velocity: %5\n")
939 .arg( note->get_instrument()->get_name() )
940 .arg( note->get_position() )
941 .arg( note->getNoteStart() )
942 .arg( note->get_velocity() ) );
951 if ( notesInSamplerQueue.size() !=
952 notesInSong.size() &&
953 pPref->m_nBufferSize < 1024 ) {
954 QString sMsg = QString(
"[testNoteEnqueuing::checkQueueConsistency] [%1] Mismatch between notes count in Song [%2] and Sampler [%3]. Song:\n" )
955 .arg( sContext ).arg( notesInSong.size() )
956 .arg( notesInSamplerQueue.size() );
957 for (
int ii = 0; ii < notesInSong.size(); ++ii ) {
958 auto note = notesInSong[ ii ];
959 sMsg.append( QString(
"\t[%1] instr: %2, position: %3, noteStart: %4, velocity: %5\n")
961 .arg( note->get_instrument()->get_name() )
962 .arg( note->get_position() )
963 .arg( note->getNoteStart() )
964 .arg( note->get_velocity() ) );
966 sMsg.append(
"SamplerQueue:\n" );
967 for (
int ii = 0; ii < notesInSamplerQueue.size(); ++ii ) {
968 auto note = notesInSamplerQueue[ ii ];
969 sMsg.append( QString(
"\t[%1] instr: %2, position: %3, noteStart: %4, velocity: %5\n")
971 .arg( note->get_instrument()->get_name() )
972 .arg( note->get_position() )
973 .arg( note->getNoteStart() )
974 .arg( note->get_velocity() ) );
980 checkQueueConsistency(
"song mode" );
989 pCoreActionController->activateSongMode(
false );
991 pHydrogen->setSelectedPatternNumber( 4 );
999 pSong->getPatternList()->get( pHydrogen->getSelectedPatternNumber() );
1000 if ( pPattern ==
nullptr ) {
1002 QString(
"[testNoteEnqueuing] null pattern selected [%1]" )
1003 .arg( pHydrogen->getSelectedPatternNumber() ) );
1007 notesInSong.clear();
1008 for (
int ii = 0; ii < nLoops; ++ii ) {
1010 if ( it->second !=
nullptr ) {
1011 auto note = std::make_shared<Note>( it->second );
1012 note->set_position( note->get_position() +
1013 ii * pPattern->get_length() );
1014 notesInSong.push_back( note );
1019 notesInSongQueue.clear();
1020 notesInSamplerQueue.clear();
1023 static_cast<int>(std::max(
static_cast<float>(pPattern->get_length()) *
1024 static_cast<float>(nLoops) *
1025 pTransportPos->getTickSize() * 4 /
1026 static_cast<float>(pPref->m_nBufferSize),
1028 static_cast<float>(nLoops) ));
1030 while ( pQueuingPos->getDoubleTick() < pPattern->get_length() * nLoops ) {
1032 nFrames = frameDist( randomEngine );
1033 pAE->updateNoteQueue( nFrames );
1034 retrieveNotes(
"pattern mode" );
1039 auto popSurplusNotes = [&]( std::vector<std::shared_ptr<Note>>* queue ) {
1040 const int nNoteNumber = queue->size();
1041 for (
int ii = 0; ii < nNoteNumber; ++ii ) {
1042 auto pNote = queue->at( nNoteNumber - 1 - ii );
1043 if ( pNote !=
nullptr &&
1044 pNote->get_position() >= pPattern->get_length() * nLoops ) {
1051 popSurplusNotes( ¬esInSongQueue );
1052 popSurplusNotes( ¬esInSamplerQueue );
1054 checkQueueConsistency(
"pattern mode" );
1066 pCoreActionController->activateLoopMode(
true );
1067 pCoreActionController->activateSongMode(
true );
1071 pAE->reset(
false );
1072 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
1077 std::max( std::ceil(
static_cast<double>(pAE->m_fSongSizeInTicks) /
1078 static_cast<double>(pPref->m_nBufferSize) *
1079 static_cast<double>(pTransportPos->getTickSize()) * 4.0 ),
1080 static_cast<double>(pAE->m_fSongSizeInTicks) ) *
1085 notesInSong.clear();
1086 for (
int ii = 0; ii <= nLoops; ++ii ) {
1087 auto notesVec = pSong->getAllNotes();
1088 for (
auto nnote : notesVec ) {
1089 nnote->set_position( nnote->get_position() +
1090 ii * pAE->m_fSongSizeInTicks );
1092 notesInSong.insert( notesInSong.end(), notesVec.begin(), notesVec.end() );
1095 notesInSongQueue.clear();
1096 notesInSamplerQueue.clear();
1099 while ( pQueuingPos->getDoubleTick() <
1100 pAE->m_fSongSizeInTicks * ( nLoops + 1 ) ) {
1102 nFrames = frameDist( randomEngine );
1105 if ( ( pTransportPos->getDoubleTick() >
1106 pAE->m_fSongSizeInTicks * nLoops + 100 ) &&
1110 pCoreActionController->activateLoopMode(
false );
1115 pAE->updateNoteQueue( nFrames );
1116 retrieveNotes(
"looped song mode" );
1119 checkQueueConsistency(
"looped song mode" );
1127 auto pSong = pHydrogen->getSong();
1128 auto pAE = pHydrogen->getAudioEngine();
1129 auto pSampler = pAE->getSampler();
1130 auto pTransportPos = pAE->getTransportPosition();
1136 std::random_device randomSeed;
1137 std::default_random_engine randomEngine( randomSeed() );
1138 std::uniform_int_distribution<int> frameDist( pPref->m_nBufferSize / 2,
1139 pPref->m_nBufferSize );
1143 pAE->reset(
false );
1144 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
1149 const int nMaxCycles =
1150 std::max( std::ceil(
static_cast<double>(pAE->m_fSongSizeInTicks) /
1151 static_cast<double>(pPref->m_nBufferSize) *
1152 static_cast<double>(pTransportPos->getTickSize()) * 4.0 ),
1153 static_cast<double>(pAE->m_fSongSizeInTicks) );
1155 auto notesInSong = pSong->getAllNotes();
1156 std::vector<std::shared_ptr<Note>> notesInSongQueue;
1157 std::vector<std::shared_ptr<Note>> notesInSamplerQueue;
1160 while ( pTransportPos->getDoubleTick() <
1161 pAE->m_fSongSizeInTicks ) {
1163 nFrames = frameDist( randomEngine );
1165 pAE->updateNoteQueue( nFrames );
1171 pAE->processAudio( nFrames );
1174 pSampler->getPlayingNotesQueue() );
1176 pAE->incrementTransportPosition( nFrames );
1179 if ( nn > nMaxCycles ) {
1181 QString(
"[testNoteEnqueuingTimeline] end of the song wasn't reached in time. pTransportPos->getFrame(): %1, pTransportPos->getDoubleTick(): %2, getTickSize(): %3, pAE->m_fSongSizeInTicks: %4, nMaxCycles: %5" )
1182 .arg( pTransportPos->getFrame() )
1183 .arg( pTransportPos->getDoubleTick(), 0,
'f' )
1184 .arg( pTransportPos->getTickSize(), 0,
'f' )
1185 .arg( pAE->m_fSongSizeInTicks, 0,
'f' )
1186 .arg( nMaxCycles ) );
1190 if ( notesInSongQueue.size() != notesInSong.size() ) {
1192 QString(
"Mismatching number of notes in song [%1] and note queue [%2]" )
1193 .arg( notesInSong.size() )
1194 .arg( notesInSongQueue.size() ) );
1197 if ( notesInSamplerQueue.size() != notesInSong.size() ) {
1199 QString(
"Mismatching number of notes in song [%1] and sampler queue [%2]" )
1200 .arg( notesInSong.size() )
1201 .arg( notesInSamplerQueue.size() ) );
1205 for (
int ii = 0; ii < notesInSong.size(); ++ii ) {
1206 if ( ! notesInSong[ ii ]->match( notesInSongQueue[ ii ] ) ) {
1208 QString(
"Mismatch at note [%1] between song [%2] and song queue [%3]" )
1211 .arg( notesInSongQueue[ ii ]->
toQString() ) );
1213 if ( ! notesInSong[ ii ]->match( notesInSamplerQueue[ ii ] ) ) {
1215 QString(
"Mismatch at note [%1] between song [%2] and sampler queue [%3]" )
1218 .arg( notesInSamplerQueue[ ii ]->
toQString() ) );
1228 auto pSong = pHydrogen->getSong();
1229 auto pAE = pHydrogen->getAudioEngine();
1230 auto pSampler = pAE->getSampler();
1231 auto pTransportPos = pAE->getTransportPosition();
1233 auto pCoreActionController = pHydrogen->getCoreActionController();
1235 pCoreActionController->activateLoopMode(
false );
1236 pCoreActionController->activateSongMode(
true );
1243 pAE->reset(
false );
1244 pAE->m_fSongSizeInTicks = pSong->lengthInTicks();
1248 auto getNotes = [&]( std::vector<std::shared_ptr<Note>> *notes ) {
1257 const double fStep = 10.0;
1258 const int nMaxCycles =
1259 std::max( std::ceil(
static_cast<double>(pAE->m_fSongSizeInTicks) /
1260 static_cast<double>(pPref->m_nBufferSize) * fStep *
1261 static_cast<double>(pTransportPos->getTickSize()) * 4.0 ),
1262 static_cast<double>(pAE->m_fSongSizeInTicks) );
1263 const uint32_t nFrames =
static_cast<uint32_t
>(
1264 std::round(
static_cast<double>(pPref->m_nBufferSize) / fStep ) );
1268 QString sPlayingPatterns;
1269 for (
const auto& pattern : *pTransportPos->getPlayingPatterns() ) {
1270 sPlayingPatterns +=
" " + pattern->get_name();
1274 while ( pTransportPos->getDoubleTick() < pAE->m_fSongSizeInTicks ||
1275 pAE->getEnqueuedNotesNumber() > 0 ) {
1277 pAE->updateNoteQueue( nFrames );
1279 pAE->processAudio( nFrames );
1282 pSampler->getPlayingNotesQueue() );
1284 pAE->incrementTransportPosition( nFrames );
1287 if ( nn > nMaxCycles ) {
1289 QString(
"[testHumanization::getNotes] end of the song wasn't reached in time. pTransportPos->getFrame(): %1, pTransportPos->getDoubleTick(): %2, getTickSize(): %3, pAE->m_fSongSizeInTicks: %4, nMaxCycles: %5" )
1290 .arg( pTransportPos->getFrame() )
1291 .arg( pTransportPos->getDoubleTick(), 0,
'f' )
1292 .arg( pTransportPos->getTickSize(), 0,
'f' )
1293 .arg( pAE->m_fSongSizeInTicks, 0,
'f' )
1294 .arg( nMaxCycles ) );
1303 auto setHumanization = [&](
double fValue ) {
1304 fValue = std::clamp( fValue, 0.0, 1.0 );
1306 pSong->setHumanizeTimeValue( fValue );
1307 pSong->setHumanizeVelocityValue( fValue );
1309 pSong->getInstrumentList()->get( 0 )->set_random_pitch_factor( fValue );
1312 auto setSwing = [&](
double fValue ) {
1313 fValue = std::clamp( fValue, 0.0, 1.0 );
1315 pSong->setSwingFactor( fValue );
1320 auto notesInSong = pSong->getAllNotes();
1323 setHumanization( 0 );
1326 std::vector<std::shared_ptr<Note>> notesReference;
1327 getNotes( ¬esReference );
1329 if ( notesReference.size() != notesInSong.size() ) {
1331 QString(
"[testHumanization] [references] Bad test setup. Mismatching number of notes [%1 : %2]" )
1332 .arg( notesReference.size() )
1333 .arg( notesInSong.size() ) );
1343 pCoreActionController->toggleGridCell( 0, 0 );
1344 pCoreActionController->toggleGridCell( 0, 1 );
1348 std::vector<std::shared_ptr<Note>> notesCustomized;
1349 getNotes( ¬esCustomized );
1351 if ( notesReference.size() != notesCustomized.size() ) {
1353 QString(
"[testHumanization] [customization] Mismatching number of notes [%1 : %2]" )
1354 .arg( notesReference.size() )
1355 .arg( notesCustomized.size() ) );
1358 for (
int ii = 0; ii < notesReference.size(); ++ii ) {
1359 auto pNoteReference = notesReference[ ii ];
1360 auto pNoteCustomized = notesCustomized[ ii ];
1362 if ( pNoteReference !=
nullptr && pNoteCustomized !=
nullptr ) {
1363 if ( pNoteReference->get_velocity() ==
1364 pNoteCustomized->get_velocity() ) {
1366 QString(
"[testHumanization] [customization] Velocity of note [%1] was not altered" )
1368 }
else if ( pNoteReference->get_lead_lag() ==
1369 pNoteCustomized->get_lead_lag() ) {
1371 QString(
"[testHumanization] [customization] Lead Lag of note [%1] was not altered" )
1373 }
else if ( pNoteReference->getNoteStart() ==
1374 pNoteCustomized->getNoteStart() ) {
1379 QString(
"[testHumanization] [customization] Note start of note [%1] was not altered" )
1381 }
else if ( pNoteReference->getPan() ==
1382 pNoteCustomized->getPan() ) {
1384 QString(
"[testHumanization] [customization] Pan of note [%1] was not altered" )
1386 }
else if ( pNoteReference->get_total_pitch() ==
1387 pNoteCustomized->get_total_pitch() ) {
1389 QString(
"[testHumanization] [customization] Total Pitch of note [%1] was not altered" )
1394 QString(
"[testHumanization] [customization] Unable to access note [%1]" )
1408 pCoreActionController->toggleGridCell( 0, 1 );
1409 pCoreActionController->toggleGridCell( 0, 0 );
1413 auto checkHumanization = [&](
double fValue, std::vector<std::shared_ptr<Note>>* pNotes ) {
1415 if ( notesReference.size() != pNotes->size() ) {
1417 QString(
"[testHumanization] [humanization] Mismatching number of notes [%1 : %2]" )
1418 .arg( notesReference.size() )
1419 .arg( pNotes->size() ) );
1422 auto checkDeviation = []( std::vector<float>* pDeviations,
float fTargetSD,
const QString& sContext ) {
1424 float fMean = std::accumulate( pDeviations->begin(), pDeviations->end(),
1425 0.0, std::plus<float>() ) /
1426 static_cast<float>( pDeviations->size() );
1429 auto compVariance = [&](
float fValue,
float fElement ) {
1430 return fValue + ( fElement - fMean ) * ( fElement - fMean );
1432 float fSD = std::sqrt( std::accumulate( pDeviations->begin(),
1434 0.0, compVariance ) /
1435 static_cast<float>( pDeviations->size() ) );
1440 if ( std::abs( fMean ) > std::abs( fSD ) * 0.5 ) {
1442 QString(
"[testHumanization] [%1] Mismatching mean [%2] != [0] with std. deviation [%3]" )
1443 .arg( sContext ).arg( fMean, 0,
'E', -1 )
1444 .arg( fSD, 0,
'E', -1 ) );
1446 if ( std::abs( fSD - fTargetSD ) > fTargetSD * 0.5 ) {
1448 QString(
"[testHumanization] [%1] Mismatching standard deviation [%2] != [%3], diff [%4]" )
1449 .arg( sContext ).arg( fSD, 0,
'E', -1 )
1450 .arg( fTargetSD, 0,
'E', -1 )
1451 .arg( fSD - fTargetSD, 0,
'E', -1 ) );
1456 std::vector<float> deviationsPitch( notesReference.size() );
1457 std::vector<float> deviationsVelocity( notesReference.size() );
1458 std::vector<float> deviationsTiming( notesReference.size() );
1460 for (
int ii = 0; ii < pNotes->size(); ++ii ) {
1461 auto pNoteReference = notesReference[ ii ];
1462 auto pNoteHumanized = pNotes->at( ii );
1464 if ( pNoteReference !=
nullptr && pNoteHumanized !=
nullptr ) {
1465 deviationsVelocity[ ii ] =
1466 pNoteReference->get_velocity() - pNoteHumanized->get_velocity();
1467 deviationsPitch[ ii ] =
1468 pNoteReference->get_pitch() - pNoteHumanized->get_pitch();
1469 deviationsTiming[ ii ] =
1470 pNoteReference->getNoteStart() - pNoteHumanized->getNoteStart();
1473 QString(
"[testHumanization] [swing] Unable to access note [%1]" )
1482 checkDeviation( &deviationsVelocity,
1484 checkDeviation( &deviationsTiming,
1487 checkDeviation( &deviationsPitch,
1491 setHumanization( 0.2 );
1492 std::vector<std::shared_ptr<Note>> notesHumanizedWeak;
1493 getNotes( ¬esHumanizedWeak );
1494 checkHumanization( 0.2, ¬esHumanizedWeak );
1496 setHumanization( 0.8 );
1497 std::vector<std::shared_ptr<Note>> notesHumanizedStrong;
1498 getNotes( ¬esHumanizedStrong );
1499 checkHumanization( 0.8, ¬esHumanizedStrong );
1509 setHumanization( 0 );
1511 std::vector<std::shared_ptr<Note>> notesSwing;
1512 getNotes( ¬esSwing );
1514 if ( notesReference.size() != notesSwing.size() ) {
1516 QString(
"[testHumanization] [swing] Mismatching number of notes [%1 : %2]" )
1517 .arg( notesReference.size() )
1518 .arg( notesSwing.size() ) );
1521 bool bNoteAltered =
false;
1522 for (
int ii = 0; ii < notesReference.size(); ++ii ) {
1523 auto pNoteReference = notesReference[ ii ];
1524 auto pNoteSwing = notesSwing[ ii ];
1526 if ( pNoteReference !=
nullptr && pNoteSwing !=
nullptr ) {
1527 if ( pNoteReference->getNoteStart() !=
1528 pNoteSwing->getNoteStart() ) {
1529 bNoteAltered =
true;
1533 QString(
"[testHumanization] [swing] Unable to access note [%1]" )
1537 if ( ! bNoteAltered ) {
1593 auto pSong = pHydrogen->getSong();
1594 auto pAE = pHydrogen->getAudioEngine();
1596 double fCheckTickMismatch;
1597 const long long nCheckFrame =
1599 pPos->getDoubleTick(), &fCheckTickMismatch );
1600 const double fCheckTick =
1603 if ( abs( fCheckTick + fCheckTickMismatch - pPos->getDoubleTick() ) > 1e-9 ||
1604 abs( fCheckTickMismatch - pPos->m_fTickMismatch ) > 1e-9 ||
1605 nCheckFrame != pPos->getFrame() ) {
1607 QString(
"[checkTransportPosition] [%8] [tick or frame mismatch]. original position: [%1], nCheckFrame: %2, fCheckTick: %3, fCheckTickMismatch: %4, fCheckTick + fCheckTickMismatch - pPos->getDoubleTick(): %5, fCheckTickMismatch - pPos->m_fTickMismatch: %6, nCheckFrame - pPos->getFrame(): %7" )
1608 .arg( pPos->toQString(
"",
true ) ).arg( nCheckFrame )
1609 .arg( fCheckTick, 0 ,
'f', 9 ).arg( fCheckTickMismatch, 0 ,
'f', 9 )
1610 .arg( fCheckTick + fCheckTickMismatch - pPos->getDoubleTick(), 0,
'E' )
1611 .arg( fCheckTickMismatch - pPos->m_fTickMismatch, 0,
'E' )
1612 .arg( nCheckFrame - pPos->getFrame() ).arg( sContext ) );
1615 long nCheckPatternStartTick;
1616 const int nCheckColumn = pHydrogen->getColumnForTick(
1617 pPos->getTick(), pSong->isLoopEnabled(), &nCheckPatternStartTick );
1618 const long nTicksSinceSongStart =
static_cast<long>(std::floor(
1619 std::fmod( pPos->getDoubleTick(), pAE->m_fSongSizeInTicks ) ));
1621 if ( pHydrogen->getMode() ==
Song::Mode::Song && pPos->getColumn() != -1 &&
1622 ( nCheckColumn != pPos->getColumn() ||
1623 ( nCheckPatternStartTick != pPos->getPatternStartTick() ) ||
1624 ( nTicksSinceSongStart - nCheckPatternStartTick !=
1625 pPos->getPatternTickPosition() ) ) ) {
1627 QString(
"[checkTransportPosition] [%7] [column or pattern tick mismatch]. current position: [%1], nCheckColumn: %2, nCheckPatternStartTick: %3, nCheckPatternTickPosition: %4, nTicksSinceSongStart: %5, pAE->m_fSongSizeInTicks: %6" )
1628 .arg( pPos->toQString(
"",
true ) ).arg( nCheckColumn )
1629 .arg( nCheckPatternStartTick )
1630 .arg( nTicksSinceSongStart - nCheckPatternStartTick )
1631 .arg( nTicksSinceSongStart ).arg( pAE->m_fSongSizeInTicks, 0,
'f' )
1637 const std::vector<std::shared_ptr<Note>> newNotes,
1638 const QString& sContext,
1639 int nPassedFrames,
bool bTestAudio,
1640 float fPassedTicks ) {
1642 auto pSong = pHydrogen->getSong();
1643 auto pAE = pHydrogen->getAudioEngine();
1644 auto pTransportPos = pAE->getTransportPosition();
1646 double fPassedFrames =
static_cast<double>(nPassedFrames);
1647 const int nSampleRate = pHydrogen->getAudioOutput()->getSampleRate();
1649 int nNotesFound = 0;
1650 for (
const auto& ppNewNote : newNotes ) {
1651 for (
const auto& ppOldNote : oldNotes ) {
1652 if ( ppNewNote->match( ppOldNote.get() ) &&
1653 ppNewNote->get_humanize_delay() ==
1654 ppOldNote->get_humanize_delay() &&
1655 ppNewNote->get_velocity() == ppOldNote->get_velocity() ) {
1661 for (
int nn = 0; nn < ppNewNote->get_instrument()->get_components()->size(); nn++ ) {
1662 auto pSelectedLayer = ppOldNote->get_layer_selected( nn );
1670 if ( ppOldNote->getSample( nn )->get_sample_rate() !=
1672 ppOldNote->get_total_pitch() != 0.0 ) {
1674 fPassedFrames =
static_cast<double>(nPassedFrames) *
1676 static_cast<float>(ppOldNote->getSample( nn )->get_sample_rate()) /
1677 static_cast<float>(nSampleRate);
1680 const int nSampleFrames =
1681 ppNewNote->get_instrument()->get_component( nn )
1682 ->get_layer( pSelectedLayer->nSelectedLayer )
1683 ->get_sample()->get_frames();
1684 const double fExpectedFrames =
1685 std::min(
static_cast<double>(pSelectedLayer->fSamplePosition) +
1687 static_cast<double>(nSampleFrames) );
1688 if ( std::abs( ppNewNote->get_layer_selected( nn )->fSamplePosition -
1689 fExpectedFrames ) > 1 ) {
1691 QString(
"[checkAudioConsistency] [%4] glitch in audio render. Diff: %9\nPre: %1\nPost: %2\nwith passed frames: %3, nSampleFrames: %5, fExpectedFrames: %6, sample sampleRate: %7, driver sampleRate: %8\n" )
1692 .arg( ppOldNote->toQString(
"",
true ) )
1693 .arg( ppNewNote->toQString(
"",
true ) )
1694 .arg( fPassedFrames, 0,
'f' ).arg( sContext )
1695 .arg( nSampleFrames ).arg( fExpectedFrames, 0,
'f' )
1696 .arg( ppOldNote->getSample( nn )->get_sample_rate() )
1698 .arg( ppNewNote->get_layer_selected( nn )->fSamplePosition -
1699 fExpectedFrames, 0,
'g', 30 ) );
1707 if ( ppNewNote->get_position() - fPassedTicks !=
1708 ppOldNote->get_position() ) {
1710 QString(
"[checkAudioConsistency] [%5] glitch in note queue.\n\tPre: %1\n\tPost: %2\n\tfPassedTicks: %3, diff (new - passed - old): %4" )
1711 .arg( ppOldNote->toQString(
"",
true ) )
1712 .arg( ppNewNote->toQString(
"",
true ) )
1713 .arg( fPassedTicks )
1714 .arg( ppNewNote->get_position() - fPassedTicks -
1715 ppOldNote->get_position() ).arg( sContext ) );
1726 if ( nNotesFound == 0 &&
1727 oldNotes.size() > 0 &&
1728 newNotes.size() > 0 ) {
1729 QString sMsg = QString(
"[checkAudioConsistency] [%1] bad test design. No notes played back." )
1731 sMsg.append(
"\nold notes:" );
1732 for (
auto const& nnote : oldNotes ) {
1733 sMsg.append(
"\n" + nnote->toQString(
" ",
true ) );
1735 sMsg.append(
"\nnew notes:" );
1736 for (
auto const& nnote : newNotes ) {
1737 sMsg.append(
"\n" + nnote->toQString(
" ",
true ) );
1739 sMsg.append( QString(
"\n\npTransportPos->getDoubleTick(): %1, pTransportPos->getFrame(): %2, nPassedFrames: %3, fPassedTicks: %4, pTransportPos->getTickSize(): %5" )
1740 .arg( pTransportPos->getDoubleTick(), 0,
'f' )
1741 .arg( pTransportPos->getFrame() )
1742 .arg( nPassedFrames )
1743 .arg( fPassedTicks, 0,
'f' )
1744 .arg( pTransportPos->getTickSize(), 0,
'f' ) );
1745 sMsg.append(
"\n\n notes in song:" );
1746 for (
auto const& nnote : pSong->getAllNotes() ) {
1747 sMsg.append(
"\n" + nnote->toQString(
" ",
true ) );
1771 auto pCoreActionController = pHydrogen->getCoreActionController();
1772 auto pSong = pHydrogen->getSong();
1773 auto pAE = pHydrogen->getAudioEngine();
1774 auto pSampler = pAE->getSampler();
1775 auto pTransportPos = pAE->getTransportPosition();
1777 const unsigned long nBufferSize = pHydrogen->getAudioOutput()->getBufferSize();
1779 pAE->updateNoteQueue( nBufferSize );
1780 pAE->processAudio( nBufferSize );
1781 pAE->incrementTransportPosition( nBufferSize );
1786 float fPrevTempo, fPrevTickSize;
1787 double fPrevTickStart, fPrevTickEnd;
1788 long long nPrevLeadLag;
1790 std::vector<std::shared_ptr<Note>> notesSamplerPreToggle,
1791 notesSamplerPostToggle, notesSamplerPostRolling;
1795 auto toggleAndCheck = [&](
const QString& sContext ) {
1796 notesSamplerPreToggle.clear();
1797 for (
const auto& ppNote : pSampler->getPlayingNotesQueue() ) {
1798 notesSamplerPreToggle.push_back( std::make_shared<Note>( ppNote ) );
1801 nPrevLeadLag = pAE->computeTickInterval( &fPrevTickStart, &fPrevTickEnd,
1803 nOldSongSize = pSong->lengthInTicks();
1804 nOldColumn = pTransportPos->getColumn();
1805 fPrevTempo = pTransportPos->getBpm();
1806 fPrevTickSize = pTransportPos->getTickSize();
1810 pCoreActionController->toggleGridCell( nToggleColumn, nToggleRow );
1814 const QString sNewContext =
1815 QString(
"toggleAndCheckConsistency::toggleAndCheck : %1 : toggling (%2,%3)" )
1816 .arg( sContext ).arg( nToggleColumn ).arg( nToggleRow );
1819 const long nNewSongSize = pSong->lengthInTicks();
1820 if ( nNewSongSize == nOldSongSize ) {
1822 QString(
"[%1] no change in song size" ).arg( sNewContext ) );
1832 notesSongQueuePreToggle, notesSongQueuePostToggle,
1833 sNewContext +
" : song queue", 0,
false,
1834 pTransportPos->getTickOffsetSongSize() );
1838 notesSongQueuePreToggle = notesSongQueuePostToggle;
1840 notesSamplerPostToggle.clear();
1841 for (
const auto& ppNote : pSampler->getPlayingNotesQueue() ) {
1842 notesSamplerPostToggle.push_back( std::make_shared<Note>( ppNote ) );
1845 notesSamplerPreToggle, notesSamplerPostToggle,
1846 sNewContext +
" : sampler queue", 0,
true,
1847 pTransportPos->getTickOffsetSongSize() );
1852 if ( nOldColumn < pSong->getPatternGroupVector()->size() ) {
1855 if ( nOldColumn != pTransportPos->getColumn() &&
1856 nOldColumn < pSong->getPatternGroupVector()->size() ) {
1858 QString(
"[%3] Column changed old: %1, new: %2" )
1859 .arg( nOldColumn ).arg( pTransportPos->getColumn() )
1860 .arg( sNewContext ) );
1863 double fTickEnd, fTickStart;
1864 const long long nLeadLag =
1865 pAE->computeTickInterval( &fTickStart, &fTickEnd, nBufferSize );
1866 if ( std::abs( nLeadLag - nPrevLeadLag ) > 1 ) {
1868 QString(
"[%3] LeadLag should be constant since there should be change in tick size. old: %1, new: %2" )
1869 .arg( nPrevLeadLag ).arg( nLeadLag ).arg( sNewContext ) );
1871 if ( std::abs( fTickStart - pTransportPos->getTickOffsetSongSize() - fPrevTickStart ) > 4e-3 ) {
1873 QString(
"[%5] Mismatch in the start of the tick interval handled by updateNoteQueue new [%1] != [%2] old+offset, old: %3, offset: %4" )
1874 .arg( fTickStart, 0,
'f' )
1875 .arg( fPrevTickStart + pTransportPos->getTickOffsetSongSize(), 0,
'f' )
1876 .arg( fPrevTickStart, 0,
'f' )
1877 .arg( pTransportPos->getTickOffsetSongSize(), 0,
'f' )
1878 .arg( sNewContext ) );
1880 if ( std::abs( fTickEnd - pTransportPos->getTickOffsetSongSize() - fPrevTickEnd ) > 4e-3 ) {
1882 QString(
"[%5] Mismatch in the end of the tick interval handled by updateNoteQueue new [%1] != [%2] old+offset, old: %3, offset: %4" )
1883 .arg( fTickEnd, 0,
'f' )
1884 .arg( fPrevTickEnd + pTransportPos->getTickOffsetSongSize(), 0,
'f' )
1885 .arg( fPrevTickEnd, 0,
'f' )
1886 .arg( pTransportPos->getTickOffsetSongSize(), 0,
'f' )
1887 .arg( sNewContext ) );
1890 else if ( pTransportPos->getColumn() != 0 &&
1891 nOldColumn >= pSong->getPatternGroupVector()->size() ) {
1893 QString(
"[%4] Column reset failed nOldColumn: %1, pTransportPos->getColumn() (new): %2, pSong->getPatternGroupVector()->size() (new): %3" )
1895 .arg( pTransportPos->getColumn() )
1896 .arg( pSong->getPatternGroupVector()->size() )
1897 .arg( sNewContext ) );
1906 pAE->incrementTransportPosition( nBufferSize );
1907 pAE->processAudio( nBufferSize );
1911 double fTickEndRolling, fTickStartUnused;
1912 pAE->computeTickInterval( &fTickStartUnused, &fTickEndRolling, nBufferSize );
1914 pAE->incrementTransportPosition( nBufferSize );
1915 pAE->processAudio( nBufferSize );
1917 pAE->m_fLastTickEnd = fTickEndRolling;
1920 if ( fPrevTempo != pTransportPos->getBpm() ||
1921 fPrevTickSize != pTransportPos->getTickSize() ) {
1923 QString(
"[%1] tempo and ticksize are affected" )
1924 .arg( sNewContext ) );
1927 notesSamplerPostRolling.clear();
1928 for (
const auto& ppNote : pSampler->getPlayingNotesQueue() ) {
1929 notesSamplerPostRolling.push_back( std::make_shared<Note>( ppNote ) );
1932 notesSamplerPostToggle, notesSamplerPostRolling,
1933 QString(
"toggleAndCheckConsistency::toggleAndCheck : %1 : rolling after toggle (%2,%3)" )
1934 .arg( sContext ).arg( nToggleColumn ).arg( nToggleRow ),
1935 nBufferSize * 2,
true );
1939 toggleAndCheck( sContext +
" : 1. toggle" );
1942 toggleAndCheck( sContext +
" : 2. toggle" );