72#define AUDIO_ENGINE_DEBUG 0
77#define AE_INFOLOG(x) INFOLOG( QString( "[%1] %2" ) \
78 .arg( Hydrogen::get_instance()->getAudioEngine()->getDriverNames() ).arg( x ) );
79#define AE_WARNINGLOG(x) WARNINGLOG( QString( "[%1] %2" ) \
80 .arg( Hydrogen::get_instance()->getAudioEngine()->getDriverNames() ).arg( x ) );
81#define AE_ERRORLOG(x) ERRORLOG( QString( "[%1] %2" ) \
82 .arg( Hydrogen::get_instance()->getAudioEngine()->getDriverNames() ).arg( x ) );
83#define AE_DEBUGLOG(x) if ( __logger->should_log( Logger::Debug ) ) { \
84 __logger->log( Logger::Debug, _class_name(), __FUNCTION__, \
85 QString( "%1" ).arg( x ), "\033[34;1m" ); }
114 , m_fLastTickEnd( 0 )
115 , m_bLookaheadApplied(
false )
118 m_pTransportPosition = std::make_shared<TransportPosition>(
"Transport" );
119 m_pQueuingPosition = std::make_shared<TransportPosition>(
"Queuing" );
122 m_pSynth =
new Synth;
126 srand( time(
nullptr ) );
131 m_pMetronomeInstrument = std::make_shared<Instrument>(
METRONOME_INSTR_ID,
"metronome" );
133 auto pLayer = std::make_shared<InstrumentLayer>(
Sample::load( sMetronomeFilename ) );
134 auto pCompo = std::make_shared<InstrumentComponent>( 0 );
135 pCompo->set_layer(pLayer, 0);
136 m_pMetronomeInstrument->get_components()->push_back( pCompo );
137 m_pMetronomeInstrument->set_is_metronome_instrument(
true);
138 m_pMetronomeInstrument->set_volume(
141 m_AudioProcessCallback = &audioEngine_process;
143#ifdef H2CORE_HAVE_LADSPA
152 AE_ERRORLOG(
"Error the audio engine is not in State::Initialized" );
158 AE_INFOLOG(
"*** Hydrogen audio engine shutdown ***" );
173#ifdef H2CORE_HAVE_LADSPA
195#ifdef H2CORE_HAVE_DEBUG
197 std::stringstream tmpStream;
198 tmpStream << std::this_thread::get_id();
201 QString(
"[thread id: %1] : %2 : [line: %3] : %4" )
202 .arg( QString::fromStdString( tmpStream.str() ) )
203 .arg( function ).arg( line ).arg( file ) );
213#ifdef H2CORE_HAVE_DEBUG
216 QString(
"[thread id: %1] locked" )
217 .arg( QString::fromStdString( tmpStream.str() ) ) );
224#ifdef H2CORE_HAVE_DEBUG
226 std::stringstream tmpStream;
227 tmpStream << std::this_thread::get_id();
230 QString(
"[thread id: %1] : %2 : [line: %3] : %4" )
231 .arg( QString::fromStdString( tmpStream.str() ) )
232 .arg( function ).arg( line ).arg( file ) );
245#ifdef H2CORE_HAVE_DEBUG
248 QString(
"[thread id: %1] locked" )
249 .arg( QString::fromStdString( tmpStream.str() ) ) );
258 std::stringstream tmpStream;
259 tmpStream << std::this_thread::get_id();
260#ifdef H2CORE_HAVE_DEBUG
263 QString(
"[thread id: %1] : %2 : [line: %3] : %4" )
264 .arg( QString::fromStdString( tmpStream.str() ) )
265 .arg( function ).arg( line ).arg( file ) );
272 AE_WARNINGLOG( QString(
"[thread id: %1] : Lock timeout: lock timeout %2:%3:%4, lock held by %5:%6:%7" )
273 .arg( QString::fromStdString( tmpStream.str() ) )
274 .arg( file ).arg( function ).arg( line )
284#ifdef H2CORE_HAVE_DEBUG
287 QString(
"[thread id: %1] locked" )
288 .arg( QString::fromStdString( tmpStream.str() ) ) );
301#ifdef H2CORE_HAVE_DEBUG
302 std::stringstream tmpStream;
303 tmpStream << std::this_thread::get_id();
306 QString(
"[thread id: %1]" )
307 .arg( QString::fromStdString( tmpStream.str() ) ) );
317 AE_ERRORLOG(
"Error the audio engine is not in State::Ready" );
331 AE_ERRORLOG( QString(
"Error the audio engine is not in State::Playing but [%1]" )
332 .arg(
static_cast<int>(
getState() ) ) );
347#ifdef H2CORE_HAVE_LADSPA
348 for (
int ii = 0; ii <
MAX_FX; ++ii ) {
368#ifdef H2CORE_HAVE_JACK
369 if ( pHydrogen->hasJackTransport() && bWithJackBroadcast ) {
379 float fTickSize = nSampleRate * 60.0 / fBpm / nResolution;
386 double fTickSize =
static_cast<double>(nSampleRate) * 60.0 /
387 static_cast<double>(fBpm) /
388 static_cast<double>(nResolution);
396 const auto pDriver = pHydrogen->getAudioOutput();
398 if ( pDriver ==
nullptr || pDriver->getSampleRate() == 0 ) {
404 static_cast<float>(pDriver->getSampleRate());
410#ifdef H2CORE_HAVE_JACK
415 if ( pHydrogen->hasJackTransport() && bWithJackBroadcast ) {
417 double fNewTick = fTick;
422 if ( std::fmod( fTick, std::floor( fTick ) ) >= 0.97 ) {
423 fNewTick = std::round( fTick );
424 AE_INFOLOG( QString(
"Tick [%1] will be rounded to [%2] in order to avoid glitches" )
425 .arg( fTick, 0,
'E', -1 ).arg( fNewTick ) );
428 double fTickMismatch;
430 fNewTick, &fTickMismatch );
432#if AUDIO_ENGINE_DEBUG
433 AE_DEBUGLOG( QString(
"[Locate via JACK server] fTick: %1, fNewTick: %2, nNewFrame: %3" )
434 .arg( fTick ).arg( fNewTick ) .arg( nNewFrame ) );
438 locateTransport( nNewFrame );
448#if AUDIO_ENGINE_DEBUG
450 .arg( fTick ).arg( nNewFrame ) );
461#if AUDIO_ENGINE_DEBUG
462 AE_DEBUGLOG( QString(
"nFrame: %1" ).arg( nFrame ) );
508#if AUDIO_ENGINE_DEBUG
509 AE_DEBUGLOG( QString(
"nFrames: %1, old frame: %2, new frame: %3, old tick: %4, new tick: %5, ticksize: %6" )
514 .arg( fNewTick, 0,
'f' )
540#ifdef H2CORE_HAVE_JACK
542 if ( pJackAudioDriver !=
nullptr ) {
549 pJackAudioDriver->makeTrackOutputs( pSong );
560#if AUDIO_ENGINE_DEBUG
561 AE_DEBUGLOG( QString(
"[Before] fTick: %1, nFrame: %2, pos: %3" )
562 .arg( fTick, 0,
'f' )
564 .arg( pPos->toQString(
"",
true ) ) );
579 bool bBBTChanged =
false;
580 const int nBar = std::max( pPos->getColumn(), 0 ) + 1;
581 if ( nBar != pPos->getBar() ) {
582 pPos->setBar( nBar );
586 const int nBeat =
static_cast<int>(
587 std::floor(
static_cast<float>(pPos->getPatternTickPosition()) / 48 )) + 1;
588 if ( pPos->getBeat() != nBeat ) {
589 pPos->setBeat( nBeat );
597#if AUDIO_ENGINE_DEBUG
598 AE_DEBUGLOG( QString(
"[After] fTick: %1, nFrame: %2, pos: %3, frame: %4" )
599 .arg( fTick, 0,
'f' )
601 .arg( pPos->toQString(
"",
true ) )
602 .arg( pPos->getFrame() ) );
611 pPos->setTick( fTick );
612 pPos->setFrame( nFrame );
614 const double fPatternStartTick =
615 static_cast<double>(pPos->getPatternStartTick());
616 const int nPatternSize = pPos->getPatternSize();
618 if ( fTick >= fPatternStartTick +
static_cast<double>(nPatternSize) ||
619 fTick < fPatternStartTick ) {
622 pPos->setPatternStartTick( pPos->getPatternStartTick() +
623 static_cast<long>(std::floor( ( fTick - fPatternStartTick ) /
624 static_cast<double>(nPatternSize) )) *
638 long nPatternTickPosition =
static_cast<long>(std::floor( fTick )) -
639 pPos->getPatternStartTick();
640 if ( nPatternTickPosition > nPatternSize ) {
641 nPatternTickPosition = (
static_cast<long>(std::floor( fTick ))
642 - pPos->getPatternStartTick() ) %
645 pPos->setPatternTickPosition( nPatternTickPosition );
650#if AUDIO_ENGINE_DEBUG
651 AE_DEBUGLOG( QString(
"[Before] fTick: %1, nFrame: %2, m_fSongSizeInTicks: %3, pos: %4" )
652 .arg( fTick, 0,
'f' )
655 .arg( pPos->toQString(
"",
true ) ) );
659 const auto pSong = pHydrogen->getSong();
661 pPos->setTick( fTick );
662 pPos->setFrame( nFrame );
665 AE_ERRORLOG( QString(
"[%1] Provided tick [%2] is negative!" )
666 .arg( pPos->getLabel() )
667 .arg( fTick, 0,
'f' ) );
672 if ( pSong ==
nullptr || pSong->getPatternGroupVector()->size() == 0 ) {
674 pPos->setPatternStartTick( 0 );
675 pPos->setPatternTickPosition( 0 );
679 long nPatternStartTick;
680 nNewColumn = pHydrogen->getColumnForTick(
681 std::floor( fTick ), pSong->isLoopEnabled(), &nPatternStartTick );
682 pPos->setPatternStartTick( nPatternStartTick );
687 if ( nNewColumn == -1 ) {
691 pPos->setPatternTickPosition( 0 );
694 pPos->setPatternTickPosition(
695 std::fmod( std::floor( fTick ) - nPatternStartTick,
699 pPos->setPatternTickPosition( std::floor( fTick ) - nPatternStartTick );
703 if ( pPos->getColumn() != nNewColumn ) {
704 pPos->setColumn( nNewColumn );
713#if AUDIO_ENGINE_DEBUG
714 AE_DEBUGLOG( QString(
"[After] fTick: %1, nFrame: %2, m_fSongSizeInTicks: %3, pos: %4, frame: %5" )
715 .arg( fTick, 0,
'f' )
718 .arg( pPos->toQString(
"",
true ) )
719 .arg( pPos->getFrame() ) );
732 auto pSong = pHydrogen->getSong();
734 const float fOldBpm = pPos->getBpm();
741 if ( pHydrogen->getJackTimebaseState() !=
743 ( ( pSong !=
nullptr && ! pSong->getIsTimelineActivated() ) ||
749 if ( fNewBpm != fOldBpm ) {
750 pPos->setBpm( fNewBpm );
757 if ( pSong !=
nullptr ) {
758 nResolution = pSong->getResolution();
763 const float fOldTickSize = pPos->getTickSize();
769#if defined(WIN32) and !defined(WIN64)
775 if ( std::abs( fNewTickSize - fOldTickSize ) < 1e-2 ) {
777 if ( fNewTickSize == fOldTickSize ) {
782 if ( fNewTickSize == 0 ) {
783 AE_ERRORLOG( QString(
"[%1] Something went wrong while calculating the tick size. [oldTS: %2, newTS: %3]" )
784 .arg( pPos->getLabel() )
785 .arg( fOldTickSize, 0,
'f' ).arg( fNewTickSize, 0,
'f' ) );
793 pPos->setLastLeadLagFactor( 0 );
795#if AUDIO_ENGINE_DEBUG
796 AE_DEBUGLOG(QString(
"[%1] [%7,%8] sample rate: %2, tick size: %3 -> %4, bpm: %5 -> %6" )
797 .arg( pPos->getLabel() )
799 .arg( fOldTickSize, 0,
'f' )
800 .arg( fNewTickSize, 0,
'f' )
801 .arg( fOldBpm, 0,
'f' )
802 .arg( pPos->getBpm(), 0,
'f' )
803 .arg( pPos->getFrame() )
804 .arg( pPos->getDoubleTick(), 0,
'f' ) );
807 pPos->setTickSize( fNewTickSize );
817 const long long nNewFrame =
819 &pPos->m_fTickMismatch );
820 pPos->setFrameOffsetTempo( nNewFrame - pPos->getFrame() +
821 pPos->getFrameOffsetTempo() );
825 const long long nNewLookahead =
829 nNewFrame + nNewLookahead ) + pPos->getTickMismatch();
832#if AUDIO_ENGINE_DEBUG
833 AE_DEBUGLOG( QString(
"[%1 : [%2] timeline] old frame: %3, new frame: %4, tick: %5, nNewLookahead: %6, pPos->getFrameOffsetTempo(): %7, pPos->getTickOffsetQueuing(): %8, fNewTickEnd: %9, m_fLastTickEnd: %10" )
834 .arg( pPos->getLabel() )
836 .arg( pPos->getFrame() )
838 .arg( pPos->getDoubleTick(), 0,
'f' )
839 .arg( nNewLookahead )
840 .arg( pPos->getFrameOffsetTempo() )
841 .arg( pPos->getTickOffsetQueuing(), 0,
'f' )
842 .arg( fNewTickEnd, 0,
'f' )
851 if ( pPos->getFrame() != nNewFrame ) {
852 pPos->setFrame( nNewFrame );
863 float *pBuffer_L, *pBuffer_R;
869 assert( pBuffer_L !=
nullptr && pBuffer_R !=
nullptr );
870 memset( pBuffer_L, 0, nFrames *
sizeof(
float ) );
871 memset( pBuffer_R, 0, nFrames *
sizeof(
float ) );
874#ifdef H2CORE_HAVE_JACK
878 if ( pJackAudioDriver !=
nullptr ) {
886#ifdef H2CORE_HAVE_LADSPA
891 for (
unsigned i = 0; i <
MAX_FX; ++i ) {
893 if ( pFX !=
nullptr ) {
896 memset( pFX->
m_pBuffer_L, 0, nFrames *
sizeof(
float ) );
897 memset( pFX->
m_pBuffer_R, 0, nFrames *
sizeof(
float ) );
911 auto pSong = pHydrogen->getSong();
919#ifdef H2CORE_HAVE_JACK
920 if (
auto pJackDriver =
dynamic_cast<JackAudioDriver*
>( pAudioDriver ) ) {
921 pJackDriver->setConnectDefaults(
956 if ( pAudioDriver ==
nullptr ) {
957 AE_INFOLOG( QString(
"Unable to create driver [%1]" )
963 int nRes = pAudioDriver->
init( pPref->m_nBufferSize );
965 AE_ERRORLOG( QString(
"Error code [%2] while initializing audio driver [%1]." )
978 if ( pSong !=
nullptr ) {
992 AE_ERRORLOG( QString(
"Error code [%2] while connecting audio driver [%1]." )
1007 if ( pSong !=
nullptr && pHydrogen->hasJackAudioDriver() ) {
1008 pHydrogen->renameJackPorts( pSong );
1014 if ( pSong !=
nullptr ) {
1021 return pAudioDriver;
1030 AE_ERRORLOG( QString(
"Audio engine is not in State::Initialized but [%1]" )
1031 .arg(
static_cast<int>(
getState() ) ) );
1057 AE_ERRORLOG( QString(
"Couldn't start audio driver [%1], falling back to NullDriver" )
1066#ifdef H2CORE_HAVE_ALSA
1074#ifdef H2CORE_HAVE_PORTMIDI
1082#ifdef H2CORE_HAVE_COREMIDI
1090#ifdef H2CORE_HAVE_JACK
1115 AE_ERRORLOG( QString(
"Audio engine is not in State::Prepared or State::Ready but [%1]" )
1116 .arg(
static_cast<int>(
m_state) ) );
1157 if ( pSong !=
nullptr &&
1177 auto pAudioEngine = pHydrogen->getAudioEngine();
1178 auto pSong = pHydrogen->getSong();
1180 if ( pSong ==
nullptr ) {
1185 float fBpm = pAudioEngine->getTransportPosition()->getBpm();
1187 if ( pHydrogen->getJackTimebaseState() ==
1192 const float fJackTimebaseBpm = pHydrogen->getJackTimebaseControllerBpm();
1193 if ( ! std::isnan( fJackTimebaseBpm ) ) {
1194 if ( fBpm != fJackTimebaseBpm ) {
1195 fBpm = fJackTimebaseBpm;
1196#if AUDIO_ENGINE_DEBUG
1197 AE_DEBUGLOG( QString(
"Tempo update by the JACK server [%1]")
1198 .arg( fJackTimebaseBpm ) );
1202 AE_ERRORLOG(
"Unable to retrieve tempo from JACK server" );
1205 else if ( pSong->getIsTimelineActivated() &&
1208 const float fTimelineBpm = pHydrogen->getTimeline()->getTempoAtColumn( nColumn );
1209 if ( fTimelineBpm != fBpm ) {
1210#if AUDIO_ENGINE_DEBUG
1211 AE_DEBUGLOG( QString(
"Set tempo to timeline value [%1]")
1212 .arg( fTimelineBpm ) );
1214 fBpm = fTimelineBpm;
1220 if ( pAudioEngine->getNextBpm() != fBpm ) {
1221#if AUDIO_ENGINE_DEBUG
1222 AE_DEBUGLOG( QString(
"BPM changed via Widget, OSC, or MIDI from [%1] to [%2]." )
1223 .arg( fBpm ).arg( pAudioEngine->getNextBpm() ) );
1236 std::shared_ptr<Song> pSong = pHydrogen->
getSong();
1237 if ( pSong ==
nullptr ) {
1241#ifdef H2CORE_HAVE_LADSPA
1242 for (
unsigned nFX = 0; nFX <
MAX_FX; ++nFX ) {
1244 if ( pFX ==
nullptr ) {
1265 const auto pSong = pHydrogen->getSong();
1267 if ( pSong !=
nullptr && pHydrogen->isPatternEditorLocked() ) {
1271 int nPatternNumber = -1;
1274 if ( nColumn < (*pSong->getPatternGroupVector()).size() ) {
1276 const auto pPatternList = pSong->getPatternList();
1277 if ( pPatternList !=
nullptr ) {
1279 const auto pColumn = ( *pSong->getPatternGroupVector() )[ nColumn ];
1282 for (
const auto& pattern : *pColumn ) {
1283 nIndex = pPatternList->index( pattern );
1285 if ( nIndex > nPatternNumber ) {
1286 nPatternNumber = nIndex;
1292 pHydrogen->setSelectedPatternNumber( nPatternNumber,
true,
true );
1298 if ( pSong ==
nullptr ) {
1311 std::shared_ptr<Song> pSong = pHydrogen->
getSong();
1312 if ( pSong ==
nullptr ) {
1332 const long long nNoteStartInFrames = pNote->
getNoteStart();
1334#if AUDIO_ENGINE_DEBUG
1335 AE_DEBUGLOG( QString(
"m_pTransportPosition->getDoubleTick(): %1, m_pTransportPosition->getFrame(): %2, nframes: %3, " )
1339 .append( pNote->
toQString(
"",
true ) ) );
1342 if ( nNoteStartInFrames < nFrame +
static_cast<long long>(nframes) ) {
1345 if ( fNoteProbability != 1. ) {
1347 if ( fNoteProbability < (
float) rand() / (
float) RAND_MAX ) {
1360 if ( pNoteInstrument->is_stop_notes() ){
1361 Note *pOffNote =
new Note( pNoteInstrument );
1382 const int nInstrument = pSong->getInstrumentList()->index( pNote->
get_instrument() );
1388 if ( nInstrument != -1 ) {
1442 if ( fSlackTime < 0.0 ) {
1453 if ( !pAudioEngine->
tryLockFor( std::chrono::microseconds( (
int)(1000.0*fSlackTime) ),
1455 ___ERRORLOG( QString(
"[%1] Failed to lock audioEngine in allowed %2 ms, missed buffer" )
1456 .arg( sDrivers ).arg( fSlackTime ) );
1476#ifdef H2CORE_HAVE_JACK
1479 if ( pAudioDriver ==
nullptr ) {
1480 ___ERRORLOG( QString(
"[%1] AudioDriver is not ready!" )
1482 assert( pAudioDriver );
1509 static_cast<long long>(nframes) );
1524 ___INFOLOG( QString(
"[%1] End of song received" ).arg( sDrivers ) );
1530 pAudioEngine->
stop();
1532 pAudioEngine->
locate( 0 );
1541 ___INFOLOG( QString(
"[%1] End of song." ).arg( sDrivers ) );
1557 ( finishTimeval.tv_sec - startTimeval.tv_sec ) * 1000.0
1558 + ( finishTimeval.tv_usec - startTimeval.tv_usec ) / 1000.0;
1569 ___WARNINGLOG( QString(
"Ladspa process time = %1" ).arg( fLadspaTime ) );
1585 if ( pSong ==
nullptr ) {
1593 assert( pBuffer_L !=
nullptr && pBuffer_R !=
nullptr );
1598 for (
unsigned i = 0; i < nFrames; ++i ) {
1599 pBuffer_L[ i ] += out_L[ i ];
1600 pBuffer_R[ i ] += out_R[ i ];
1606 for (
unsigned i = 0; i < nFrames; ++i ) {
1607 pBuffer_L[ i ] += out_L[ i ];
1608 pBuffer_R[ i ] += out_R[ i ];
1613#ifdef H2CORE_HAVE_LADSPA
1614 for (
unsigned nFX = 0; nFX <
MAX_FX; ++nFX ) {
1616 if ( ( pFX ) && ( pFX->
isEnabled() ) ) {
1619 float *buf_L, *buf_R;
1628 for (
unsigned i = 0; i < nFrames; ++i ) {
1629 pBuffer_L[ i ] += buf_L[ i ];
1630 pBuffer_R[ i ] += buf_R[ i ];
1644 ( ladspaTime_end.tv_sec - ladspaTime_start.tv_sec ) * 1000.0
1645 + ( ladspaTime_end.tv_usec - ladspaTime_start.tv_usec ) / 1000.0;
1648 for (
unsigned i = 0; i < nFrames; ++i ) {
1649 val_L = pBuffer_L[i];
1650 val_R = pBuffer_R[i];
1661 for (
auto component : *pSong->getComponents() ) {
1663 for (
unsigned i = 0; i < nFrames; ++i ) {
1664 float compo_val_L = pComponent->
get_out_L(i);
1665 float compo_val_R = pComponent->
get_out_R(i);
1667 if( compo_val_L > pComponent->
get_peak_l() ) {
1670 if( compo_val_R > pComponent->
get_peak_r() ) {
1686 AE_WARNINGLOG( QString(
"Provided bpm %1 is too high. Assigning upper bound %2 instead" )
1687 .arg( fNextBpm ).arg(
MAX_BPM ) );
1689 else if ( fNextBpm <
MIN_BPM ) {
1691 AE_WARNINGLOG( QString(
"Provided bpm %1 is too low. Assigning lower bound %2 instead" )
1692 .arg( fNextBpm ).arg(
MIN_BPM ) );
1703 .arg( pNewSong !=
nullptr ? pNewSong->getName() :
"nullptr" ) );
1706 AE_ERRORLOG( QString(
"Error the audio engine is not in State::Prepared but [%1]" )
1707 .arg(
static_cast<int>(
getState() ) ) );
1715 if ( pNewSong !=
nullptr ) {
1716 fNextBpm = pNewSong->getBpm();
1728 pHydrogen->renameJackPorts( pNewSong );
1734 if ( pNewSong !=
nullptr ) {
1735 pHydrogen->setTimeline( pNewSong->getTimeline() );
1736 pHydrogen->getTimeline()->activate();
1739 pHydrogen->setTimeline(
nullptr );
1753 AE_ERRORLOG( QString(
"Error the audio engine is not in State::Ready but [%1]" )
1754 .arg(
static_cast<int>(
getState() ) ) );
1768 auto pSong = pHydrogen->getSong();
1770 if ( pSong ==
nullptr ) {
1775 auto updatePatternSize = []( std::shared_ptr<TransportPosition> pPos ) {
1776 if ( pPos->getPlayingPatterns()->size() > 0 ) {
1778 pPos->setPatternSize( pPos->getPlayingPatterns()->longest_pattern_length(
false ) );
1787 AE_INFOLOG( QString(
"[Pattern] Size update: [%1] -> [%2]" )
1789 .arg(
static_cast<double>( pSong->lengthInTicks() ) ) );
1803 const double fNewSongSizeInTicks =
static_cast<double>( pSong->lengthInTicks() );
1807 const bool bEmptySong =
1810 double fNewStrippedTick, fRepetitions;
1828#if AUDIO_ENGINE_DEBUG
1829 AE_DEBUGLOG( QString(
"[Before] fNewStrippedTick: %1, fRepetitions: %2, m_fSongSizeInTicks: %3, fNewSongSizeInTicks: %4, transport: %5, queuing: %6" )
1830 .arg( fNewStrippedTick, 0,
'f' )
1831 .arg( fRepetitions )
1833 .arg( fNewSongSizeInTicks )
1839 AE_INFOLOG( QString(
"[Song] Size update: [%1] -> [%2]" )
1844 auto endOfSongReached = [&](){
1851#if AUDIO_ENGINE_DEBUG
1852 AE_DEBUGLOG( QString(
"[End of song reached] fNewStrippedTick: %1, fRepetitions: %2, m_fSongSizeInTicks: %3, fNewSongSizeInTicks: %4, transport: %5, queuing: %6" )
1853 .arg( fNewStrippedTick, 0,
'f' )
1854 .arg( fRepetitions )
1856 .arg( fNewSongSizeInTicks )
1865 if ( nOldColumn >= pSong->getPatternGroupVector()->size() &&
1873 const long nNewPatternStartTick = pHydrogen->getTickForColumn( nOldColumn );
1875 if ( nNewPatternStartTick == -1 &&
1888#if AUDIO_ENGINE_DEBUG
1889 AE_DEBUGLOG( QString(
"[nPatternStartTick mismatch] old: %1, new: %2" )
1891 .arg( nNewPatternStartTick ) );
1895 static_cast<double>(nNewPatternStartTick -
1899#ifdef H2CORE_HAVE_DEBUG
1900 const long nNewPatternTickPosition =
1901 static_cast<long>(std::floor( fNewStrippedTick )) - nNewPatternStartTick;
1904 AE_ERRORLOG( QString(
"[nPatternTickPosition mismatch] old: %1, new: %2" )
1906 .arg( nNewPatternTickPosition ) );
1911 const double fNewTick = fNewStrippedTick + fRepetitions * fNewSongSizeInTicks;
1926 fTickOffset = std::round( fTickOffset );
1927 fTickOffset *= 1e-8;
1938#if AUDIO_ENGINE_DEBUG
1939 AE_DEBUGLOG(QString(
"[update] nNewFrame: %1, m_pTransportPosition->getFrame() (old): %2, m_pTransportPosition->getFrameOffsetTempo(): %3, fNewTick: %4, m_pTransportPosition->getDoubleTick() (old): %5, m_pTransportPosition->getTickOffsetSongSize() : %6, tick offset (without rounding): %7, fNewSongSizeInTicks: %8, fRepetitions: %9, fNewStrippedTick: %10, nNewPatternStartTick: %11")
1943 .arg( fNewTick, 0,
'g', 30 )
1947 .arg( fNewSongSizeInTicks, 0,
'g', 30 )
1948 .arg( fRepetitions, 0,
'f' )
1949 .arg( fNewStrippedTick, 0,
'f' )
1950 .arg( nNewPatternStartTick )
1960#if defined(WIN32) and !defined(WIN64)
1986#ifdef H2CORE_HAVE_DEBUG
1989 AE_ERRORLOG( QString(
"[nColumn mismatch] old: %1, new: %2" )
2001#if AUDIO_ENGINE_DEBUG
2002 AE_DEBUGLOG( QString(
"[After] fNewTick: %1, fRepetitions: %2, m_fSongSizeInTicks: %3, fNewSongSizeInTicks: %4, transport: %5, queuing: %6" )
2003 .arg( fNewTick, 0,
'g', 30 )
2004 .arg( fRepetitions, 0,
'f' )
2006 .arg( fNewSongSizeInTicks )
2016 auto removePattern = [&]( std::shared_ptr<TransportPosition> pPos ) {
2017 auto pPlayingPatterns = pPos->getPlayingPatterns();
2019 for (
int ii = 0; ii < pPlayingPatterns->size(); ++ii ) {
2020 if ( pPlayingPatterns->get( ii ) == pPattern ) {
2021 pPlayingPatterns->del( ii );
2038 auto pSong = pHydrogen->getSong();
2039 auto pPlayingPatterns = pPos->getPlayingPatterns();
2041#if AUDIO_ENGINE_DEBUG
2042 AE_DEBUGLOG( QString(
"pre: %1" ).arg( pPos->toQString() ) );
2045 if ( pSong ==
nullptr ) {
2046 pPlayingPatterns->clear();
2053 const auto nPrevPatternNumber = pPlayingPatterns->size();
2055 pPlayingPatterns->clear();
2057 if ( pSong->getPatternGroupVector()->size() == 0 ) {
2068 auto nColumn = std::max( pPos->getColumn(), 0 );
2069 if ( nColumn >= pSong->getPatternGroupVector()->size() ) {
2070 AE_ERRORLOG( QString(
"Provided column [%1] exceeds allowed range [0,%2]. Using 0 as fallback." )
2072 .arg( pSong->getPatternGroupVector()->size() - 1 ) );
2076 for (
const auto& ppattern : *( *( pSong->getPatternGroupVector() ) )[ nColumn ] ) {
2077 if ( ppattern !=
nullptr ) {
2078 pPlayingPatterns->add( ppattern,
true );
2087 ( nPrevPatternNumber != 0 || pPlayingPatterns->size() != 0 ) ) {
2093 auto pSelectedPattern =
2094 pSong->getPatternList()->get( pHydrogen->getSelectedPatternNumber() );
2096 if ( pSelectedPattern !=
nullptr &&
2097 ! ( pPlayingPatterns->size() == 1 &&
2098 pPlayingPatterns->get( 0 ) == pSelectedPattern ) ) {
2099 pPlayingPatterns->clear();
2100 pPlayingPatterns->add( pSelectedPattern,
true );
2111 auto pNextPatterns = pPos->getNextPatterns();
2113 if ( pNextPatterns->size() > 0 ) {
2114 for (
const auto& ppattern : *pNextPatterns ) {
2115 if ( ppattern ==
nullptr ) {
2119 if ( ( pPlayingPatterns->del( ppattern ) ) ==
nullptr ) {
2122 pPlayingPatterns->add( ppattern,
true );
2126 ppattern->removeFlattenedVirtualPatterns( pPlayingPatterns );
2135 pNextPatterns->clear();
2139 if ( pPlayingPatterns->size() > 0 ) {
2141 pPos->setPatternSize( pPlayingPatterns->longest_pattern_length(
false ) );
2146#if AUDIO_ENGINE_DEBUG
2147 AE_DEBUGLOG( QString(
"post: %1" ).arg( pPos->toQString() ) );
2154 auto pSong = pHydrogen->getSong();
2155 if ( pSong ==
nullptr ) {
2158 auto pPatternList = pSong->getPatternList();
2159 auto pPattern = pPatternList->get( nPatternNumber );
2160 if ( pPattern ==
nullptr ) {
2179 auto pSong = pHydrogen->getSong();
2180 if ( pSong ==
nullptr ) {
2183 auto pPatternList = pSong->getPatternList();
2185 bool bAlreadyPlaying =
false;
2190 auto pRequestedPattern = pPatternList->get( nPatternNumber );
2192 auto flushAndAddNext = [&]( std::shared_ptr<TransportPosition> pPos ) {
2194 auto pNextPatterns = pPos->getNextPatterns();
2195 auto pPlayingPatterns = pPos->getPlayingPatterns();
2197 pNextPatterns->clear();
2198 for (
int ii = 0; ii < pPlayingPatterns->size(); ++ii ) {
2200 auto pPlayingPattern = pPlayingPatterns->get( ii );
2201 if ( pPlayingPattern != pRequestedPattern ) {
2202 pNextPatterns->add( pPlayingPattern );
2204 else if ( pRequestedPattern !=
nullptr ) {
2205 bAlreadyPlaying =
true;
2210 if ( ! bAlreadyPlaying && pRequestedPattern !=
nullptr ) {
2211 pNextPatterns->add( pRequestedPattern );
2222 auto copyPlayingPatterns = [&]( std::shared_ptr<TransportPosition> pPos ) {
2223 auto pPlayingPatterns = pPos->getPlayingPatterns();
2224 auto pNextPatterns = pPos->getNextPatterns();
2226 for (
const auto& ppPattern : *pPlayingPatterns ) {
2227 pNextPatterns->add( ppPattern );
2243#if AUDIO_ENGINE_DEBUG
2253#if defined(WIN32) and !defined(WIN64)
2271#if AUDIO_ENGINE_DEBUG
2281 std::vector<Note*> notes;
2286 if ( notes.size() > 0 ) {
2287 for (
auto nnote : notes ) {
2288 nnote->computeNoteStart();
2299 if ( notes.size() > 0 ) {
2300 for (
auto nnote : notes ) {
2301 nnote->computeNoteStart();
2313 std::vector<Note*> notes;
2318 const long nTickOffset =
2321 if ( notes.size() > 0 ) {
2322 for (
auto nnote : notes ) {
2324#if AUDIO_ENGINE_DEBUG
2325 AE_DEBUGLOG( QString(
"[song queue] name: %1, pos: %2 -> %3, tick offset: %4, tick offset floored: %5" )
2326 .arg( nnote->get_instrument()->get_name() )
2327 .arg( nnote->get_position() )
2328 .arg( std::max( nnote->get_position() + nTickOffset,
2329 static_cast<long>(0) ) )
2331 .arg( nTickOffset ) );
2334 nnote->set_position( std::max( nnote->get_position() + nTickOffset,
2335 static_cast<long>(0) ) );
2336 nnote->computeNoteStart();
2347 if ( notes.size() > 0 ) {
2348 for (
auto nnote : notes ) {
2350#if AUDIO_ENGINE_DEBUG
2351 AE_DEBUGLOG( QString(
"[midi queue] name: %1, pos: %2 -> %3, tick offset: %4, tick offset floored: %5" )
2352 .arg( nnote->get_instrument()->get_name() )
2353 .arg( nnote->get_position() )
2354 .arg( std::max( nnote->get_position() + nTickOffset,
2355 static_cast<long>(0) ) )
2357 .arg( nTickOffset ) );
2360 nnote->set_position( std::max( nnote->get_position() + nTickOffset,
2361 static_cast<long>(0) ) );
2362 nnote->computeNoteStart();
2376 long long nFrameStart, nFrameEnd;
2389 nFrameStart = pPos->getFrame();
2411 if ( pPos->getLastLeadLagFactor() != 0 ) {
2412 if ( pPos->getLastLeadLagFactor() != nLeadLagFactor ) {
2413 nLeadLagFactor = pPos->getLastLeadLagFactor();
2416 pPos->setLastLeadLagFactor( nLeadLagFactor );
2419 const long long nLookahead = nLeadLagFactor +
2422 nFrameEnd = nFrameStart + nLookahead +
2423 static_cast<long long>(nIntervalLengthInFrames);
2430 nFrameStart += nLookahead;
2434 pPos->getTickMismatch() ) - pPos->getTickOffsetQueuing() ;
2436 pPos->getTickOffsetQueuing();
2438#if AUDIO_ENGINE_DEBUG
2439 AE_DEBUGLOG( QString(
"nFrame: [%1,%2], fTick: [%3, %4], fTick (without offset): [%5,%6], m_pTransportPosition->getTickOffsetQueuing(): %7, nLookahead: %8, nIntervalLengthInFrames: %9, m_pTransportPosition: %10, m_pQueuingPosition: %11,_bLookaheadApplied: %12" )
2442 .arg( *fTickStart, 0,
'f' )
2443 .arg( *fTickEnd, 0,
'f' )
2446 .arg( pPos->getTickOffsetQueuing(), 0,
'f' )
2448 .arg( nIntervalLengthInFrames )
2449 .arg( pPos->toQString() )
2455 return nLeadLagFactor;
2468 if ( std::ceil( fTick ) - fTick > 0 &&
2469 std::ceil( fTick ) - fTick < 1E-6 ) {
2470 return std::floor( fTick ) + 1;
2473 return std::floor( fTick );
2480 std::shared_ptr<Song> pSong = pHydrogen->
getSong();
2481 if ( pSong ==
nullptr ) {
2485 double fTickStartComp, fTickEndComp;
2487 long long nLeadLagFactor =
2509 AutomationPath* pAutomationPath = pSong->getVelocityAutomationPath();
2519 const long nTickStart =
static_cast<long>(
coarseGrainTick( fTickStartComp ));
2520 const long nTickEnd =
static_cast<long>(
coarseGrainTick( fTickEndComp ));
2527#if AUDIO_ENGINE_DEBUG
2528 AE_DEBUGLOG( QString(
"tick interval (floor): [%1,%2], tick interval (computed): [%3,%4], nLeadLagFactor: %5, m_fSongSizeInTicks: %6, m_pTransportPosition: %7, m_pQueuingPosition: %8")
2529 .arg( nTickStart ).arg( nTickEnd )
2530 .arg( fTickStartComp, 0,
'f' ).arg( fTickEndComp, 0,
'f' )
2531 .arg( nLeadLagFactor )
2539 for (
long nnTick = nTickStart; nnTick < nTickEnd; ++nnTick ) {
2549 static_cast<double>(nnTick),
2562 static_cast<double>(nnTick),
2571 int nMetronomeTickPosition;
2572 if ( pSong->getPatternGroupVector()->size() == 0 ) {
2573 nMetronomeTickPosition = nnTick;
2578 if ( nMetronomeTickPosition % 48 == 0 ) {
2585 if ( nMetronomeTickPosition == 0 ) {
2609 pSong->getPatternGroupVector()->size() == 0 ) {
2628 if ( pPlayingPatterns->size() != 0 ) {
2629 for (
auto nPat = 0; nPat < pPlayingPatterns->size(); ++nPat ) {
2630 Pattern *pPattern = pPlayingPatterns->get( nPat );
2631 assert( pPattern !=
nullptr );
2640 Note *pNote = it->second;
2647 Note *pCopiedNote =
new Note( pNote );
2658 static_cast<float>(nLeadLagFactor) ));
2674 pCopiedNote->
swing();
2702 static_cast<long>(pCopiedNote->
get_length()),
2707#if AUDIO_ENGINE_DEBUG
2708 AE_DEBUGLOG( QString(
"m_pQueuingPosition: %1, new note: %2" )
2729 AE_ERRORLOG( QString(
"Error the audio engine is not in State::Ready, State::Playing, or State::Testing but [%1]" )
2730 .arg(
static_cast<int>(
getState() ) ) );
2746#ifdef H2CORE_HAVE_JACK
2765#ifdef H2CORE_HAVE_JACK
2768#if AUDIO_ENGINE_DEBUG
2779#if AUDIO_ENGINE_DEBUG
2792 const long long nFrameStart =
2794 const long long nFrameEnd =
2799#if AUDIO_ENGINE_DEBUG
2800 AE_DEBUGLOG( QString(
"nFrameStart: %1, nFrameEnd: %2, diff: %3, fTick: %4" )
2801 .arg( nFrameStart ).arg( nFrameEnd )
2802 .arg( nFrameEnd - nFrameStart ).arg( fTick, 0,
'f' ) );
2805 return nFrameEnd - nFrameStart;
2825 return "Uninitialized";
2827 return "Initialized";
2837 return "Unknown state";
2846 sOutput = QString(
"%1[AudioEngine]\n" ).arg( sPrefix )
2847 .append(
"%1%2m_pTransportPosition:\n").arg( sPrefix ).arg( s );
2849 sOutput.append( QString(
"%1" )
2852 sOutput.append( QString(
"nullptr\n" ) );
2854 sOutput.append( QString(
"%1%2m_pQueuingPosition:\n").arg( sPrefix ).arg( s ) );
2856 sOutput.append( QString(
"%1" )
2859 sOutput.append( QString(
"nullptr\n" ) );
2861 sOutput.append( QString(
"%1%2m_fNextBpm: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fNextBpm, 0,
'f' ) )
2862 .append( QString(
"%1%2m_state: %3\n" ).arg( sPrefix ).arg( s ).arg(
static_cast<int>(
m_state) ) )
2863 .append( QString(
"%1%2m_nextState: %3\n" ).arg( sPrefix ).arg( s ).arg(
static_cast<int>(
m_nextState) ) )
2864 .append( QString(
"%1%2m_fSongSizeInTicks: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fSongSizeInTicks, 0,
'f' ) )
2865 .append( QString(
"%1%2m_fLastTickEnd: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fLastTickEnd, 0,
'f' ) )
2866 .append( QString(
"%1%2m_bLookaheadApplied: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_bLookaheadApplied ) )
2867 .append( QString(
"%1%2m_pSampler: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2868 .append( QString(
"%1%2m_pSynth: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2869 .append( QString(
"%1%2m_pAudioDriver: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2870 .append( QString(
"%1%2m_pMidiDriver: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2871 .append( QString(
"%1%2m_pMidiDriverOut: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2872 .append( QString(
"%1%2m_pEventQueue: stringification not implemented\n" ).arg( sPrefix ).arg( s ) );
2873#ifdef H2CORE_HAVE_LADSPA
2874 sOutput.append( QString(
"%1%2m_fFXPeak_L: [" ).arg( sPrefix ).arg( s ) );
2876 sOutput.append( QString(
" %1" ).arg( ii ) );
2878 sOutput.append( QString(
"]\n%1%2m_fFXPeak_R: [" ).arg( sPrefix ).arg( s ) );
2880 sOutput.append( QString(
" %1" ).arg( ii ) );
2882 sOutput.append( QString(
" ]\n" ) );
2884 sOutput.append( QString(
"%1%2m_fMasterPeak_L: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fMasterPeak_L ) )
2885 .append( QString(
"%1%2m_fMasterPeak_R: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fMasterPeak_R ) )
2886 .append( QString(
"%1%2m_fProcessTime: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fProcessTime ) )
2887 .append( QString(
"%1%2m_fMaxProcessTime: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fMaxProcessTime ) )
2888 .append( QString(
"%1%2m_fLadspaTime: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fLadspaTime ) )
2889 .append( QString(
"%1%2m_nRealtimeFrame: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_nRealtimeFrame ) )
2890 .append( QString(
"%1%2m_AudioProcessCallback: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2891 .append( QString(
"%1%2m_songNoteQueue: length = %3\n" ).arg( sPrefix ).arg( s ).arg(
m_songNoteQueue.size() ) );
2892 sOutput.append( QString(
"%1%2m_midiNoteQueue: [\n" ).arg( sPrefix ).arg( s ) );
2894 sOutput.append( nn->toQString( sPrefix + s, bShort ) );
2896 sOutput.append( QString(
"]\n%1%2m_pMetronomeInstrument: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_pMetronomeInstrument->toQString( sPrefix + s, bShort ) ) )
2904 sOutput = QString(
"%1[AudioEngine]" ).arg( sPrefix )
2905 .append(
", m_pTransportPosition:\n");
2907 sOutput.append( QString(
"%1" )
2910 sOutput.append( QString(
"nullptr\n" ) );
2912 sOutput.append(
", m_pQueuingPosition:\n");
2914 sOutput.append( QString(
"%1" )
2917 sOutput.append( QString(
"nullptr\n" ) );
2919 sOutput.append( QString(
", m_fNextBpm: %1" ).arg(
m_fNextBpm, 0,
'f' ) )
2920 .append( QString(
", m_state: %1" ).arg(
static_cast<int>(
m_state) ) )
2921 .append( QString(
", m_nextState: %1" ).arg(
static_cast<int>(
m_nextState) ) )
2923 .append( QString(
", m_fLastTickEnd: %1" ).arg(
m_fLastTickEnd, 0,
'f' ) )
2925 .append( QString(
", m_pSampler: ..." ) )
2926 .append( QString(
", m_pSynth: ..." ) )
2927 .append( QString(
", m_pAudioDriver: ..." ) )
2928 .append( QString(
", m_pMidiDriver: ..." ) )
2929 .append( QString(
", m_pMidiDriverOut: ..." ) )
2930 .append( QString(
", m_pEventQueue: ..." ) );
2931#ifdef H2CORE_HAVE_LADSPA
2932 sOutput.append( QString(
", m_fFXPeak_L: [" ) );
2934 sOutput.append( QString(
" %1" ).arg( ii ) );
2936 sOutput.append( QString(
"], m_fFXPeak_R: [" ) );
2938 sOutput.append( QString(
" %1" ).arg( ii ) );
2940 sOutput.append( QString(
" ]" ) );
2942 sOutput.append( QString(
", m_fMasterPeak_L: %1" ).arg(
m_fMasterPeak_L ) )
2944 .append( QString(
", m_fProcessTime: %1" ).arg(
m_fProcessTime ) )
2946 .append( QString(
", m_fLadspaTime: %1" ).arg(
m_fLadspaTime ) )
2948 .append( QString(
", m_AudioProcessCallback: ..." ) )
2949 .append( QString(
", m_songNoteQueue: length = %1" ).arg(
m_songNoteQueue.size() ) );
2950 sOutput.append( QString(
", m_midiNoteQueue: [" ) );
2952 sOutput.append( nn->toQString( sPrefix + s, bShort ) );
2954 sOutput.append( QString(
"], m_pMetronomeInstrument: id = %1" ).arg(
m_pMetronomeInstrument->get_id() ) )
2966 QString sMidiInputDriver(
"unknown" );
2967 QString sMidiOutputDriver(
"unknown" );
3001 sMidiInputDriver =
"nullptr";
3002#ifdef H2CORE_HAVE_ALSA
3004 sMidiInputDriver =
"ALSA";
3006#ifdef H2CORE_HAVE_PORTMIDI
3008 sMidiInputDriver =
"PortMidi";
3010#ifdef H2CORE_HAVE_COREMIDI
3012 sMidiInputDriver =
"CoreMidi";
3014#ifdef H2CORE_HAVE_JACK
3016 sMidiInputDriver =
"JACK";
3021 sMidiOutputDriver =
"nullptr";
3022#ifdef H2CORE_HAVE_ALSA
3024 sMidiOutputDriver =
"ALSA";
3026#ifdef H2CORE_HAVE_PORTMIDI
3028 sMidiOutputDriver =
"PortMidi";
3030#ifdef H2CORE_HAVE_COREMIDI
3032 sMidiOutputDriver =
"CoreMidi";
3034#ifdef H2CORE_HAVE_JACK
3036 sMidiOutputDriver =
"JACK";
3040 auto res = QString(
"%1|" )
3042 if ( sMidiInputDriver == sMidiOutputDriver ) {
3043 res.append( QString(
"%1" ).arg( sMidiInputDriver ) );
3045 res.append( QString(
"in: %1;out: %2" ).arg( sMidiInputDriver )
3046 .arg( sMidiOutputDriver ) );
3049 return std::move( res );
3054 const QString& sMsg ) {
3058 std::stringstream tmpStream;
3059 tmpStream << std::this_thread::get_id();
3060 ERRORLOG( QString(
"[thread id: %1] [%2::%3] %4" )
3061 .arg( QString::fromStdString( tmpStream.str() ) )
3062 .arg( sClass ).arg( sFunction ).arg( sMsg ) );
3070 const char* sFunction,
3071 const QString& sMsg )
const
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
#define METRONOME_INSTR_ID
Created Instrument will be used as metronome.
#define FOREACH_NOTE_CST_IT_BOUND_LENGTH(_notes, _it, _bound, _pattern)
Iterate over all notes in column _bound in an immutable way if it is contained in _pattern.
int gettimeofday(struct timeval *tv, struct timezone *tz)
Alsa Midi Driver Based on Matthias Nagorni alsa sequencer example.
void assertAudioEngineLocked(const QString &sClass, const char *sFunction, const QString &sMsg) const
Assert that the AudioEngine lock is held if needed.
int m_nLoopsDone
Indicates how many loops the transport already did when the user presses the Loop button again.
void makeTrackPorts(std::shared_ptr< Song > pSong)
void updateBpmAndTickSize(std::shared_ptr< TransportPosition > pTransportPosition)
void handleTimelineChange()
Updates the transport states and all notes in m_songNoteQueue and m_midiNoteQueue after adding or del...
QString getDriverNames() const
void flushAndAddNextPattern(int nPatternNumber)
Add pattern nPatternNumber to #m_pNextPatterns as well as the whole content of #m_pPlayingPatterns.
std::shared_ptr< TransportPosition > m_pTransportPosition
MidiOutput * m_pMidiDriverOut
friend void Hydrogen::removeSong()
Is allowed to call removeSong().
void setRealtimeFrame(long long nFrame)
bool tryLock(const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
friend void Hydrogen::setSong(std::shared_ptr< Song > pSong, bool bRelinking)
Is allowed to call setSong().
AudioOutput * m_pAudioDriver
void handleSelectedPattern()
Keeps the selected pattern in line with the one the transport position resides in while in Song::Mode...
const PatternList * getNextPatterns() const
std::deque< Note * > m_midiNoteQueue
Midi Note FIFO.
static float getBpmAtColumn(int nColumn)
void clearAudioBuffers(uint32_t nFrames)
Clear all audio buffers.
void setNextState(State state)
static constexpr float fHumanizePitchSD
Maximum value the standard deviation of the Gaussian distribution the random pitch contribution will ...
audioProcessCallback m_AudioProcessCallback
void handleLoopModeChanged()
In order to properly support H2Core::Song::LoopMode::Finishing - transport was already looped a coupl...
void toggleNextPattern(int nPatternNumber)
Add pattern nPatternNumber to #m_pNextPatterns or deletes it in case it is already present.
static QString StateToQString(const State &state)
void setState(State state)
std::timed_mutex m_EngineMutex
Mutex for synchronizing the access to the Song object and the AudioEngine.
void removePlayingPattern(Pattern *pPattern)
long long m_nRealtimeFrame
Variable keeping track of the transport position in realtime.
@ Prepared
Drivers are set up, but not ready to process audio.
@ Initialized
Not ready, but most pointers are now valid or NULL.
@ Playing
Transport is rolling.
@ Ready
Ready to process audio.
@ Uninitialized
Not even the constructors have been called.
@ Testing
State used during the unit tests of the AudioEngine.
float getElapsedTime() const
void setNextBpm(float fNextBpm)
Stores the new speed into a separate variable which will be adopted during the next processing cycle.
State m_nextState
State assigned during the next call to processTransport().
void locateToFrame(const long long nFrame)
Version of the locate() function intended to be directly used by frame-based audio drivers / servers.
void updatePlayingPatternsPos(std::shared_ptr< TransportPosition > pPos)
void updateTransportPosition(double fTick, long long nFrame, std::shared_ptr< TransportPosition > pPos)
long long getLeadLagInFrames(double fTick)
Calculates lead lag factor (in frames) relative to the transport position fTick.
void play()
Marks the audio engine to be started during the next call of the audioEngine_process() callback funct...
static constexpr float fHumanizeTimingSD
Maximum value the standard deviation of the Gaussian distribution the random pitch contribution will ...
void updatePlayingPatterns()
Update the list of currently played patterns associated with m_pTransportPosition and m_pQueuingPosit...
static constexpr int nMaxTimeHumanize
Maximum time (in frames) a note's position can be off due to the humanization (lead-lag).
std::priority_queue< Note *, std::deque< Note * >, compare_pNotes > m_songNoteQueue
void updateVirtualPatterns()
void handleTempoChange()
Updates all notes in m_songNoteQueue and m_midiNoteQueue to be still valid after a tempo change.
float m_fFXPeak_L[MAX_FX]
bool tryLockFor(std::chrono::microseconds duration, const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
State getNextState() const
AudioOutput * createAudioDriver(const Preferences::AudioDriver &driver)
Create an audio driver using audioEngine_process() as its argument based on the provided choice and c...
void handleSongModeChanged()
Called whenever Hydrogen switches from Song::Mode::Song into Song::Mode::Pattern or the other way aro...
EventQueue * m_pEventQueue
QMutex m_MutexOutputPointer
Mutex for locking the pointer to the audio output buffer, allowing multiple readers.
double m_fSongSizeInTicks
Set to the total number of ticks in a Song.
friend class JackAudioDriver
bool isEndOfSongReached(std::shared_ptr< TransportPosition > pPos) const
void stop()
Marks the audio engine to be stopped during the next call of the audioEngine_process() callback funct...
void calculateTransportOffsetOnBpmChange(std::shared_ptr< TransportPosition > pTransportPosition)
void unlock()
Mutex unlocking of the AudioEngine.
void lock(const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
const PatternList * getPlayingPatterns() const
State m_state
Current state of the H2Core::AudioEngine.
double coarseGrainTick(double fTick)
Ideally we just floor the provided tick.
static double getLeadLagInTicks()
Maximum lead lag factor in ticks.
std::shared_ptr< TransportPosition > m_pQueuingPosition
static constexpr float fHumanizeVelocitySD
Maximum value the standard deviation of the Gaussian distribution the random velocity contribution wi...
static float computeTickSize(const int nSampleRate, const float fBpm, const int nResolution)
Calculates the number of frames that make up a tick.
void updatePatternTransportPosition(double fTick, long long nFrame, std::shared_ptr< TransportPosition > pPos)
static int audioEngine_process(uint32_t nframes, void *arg)
Main audio processing function called by the audio drivers whenever there is work to do.
struct H2Core::AudioEngine::_locker_struct m_pLocker
void locate(const double fTick, bool bWithJackBroadcast=true)
void processPlayNotes(unsigned long nframes)
void updateSongSize()
Function to be called every time the length of the current song does change, e.g.
Sampler * getSampler() const
void stopAudioDrivers()
Stops all audio and MIDI drivers.
void restartAudioDrivers()
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
std::shared_ptr< Instrument > m_pMetronomeInstrument
Pointer to the metronome.
void handleSongSizeChange()
Updates all notes in m_songNoteQueue to be still valid after a change in song size.
void assertLocked(const QString &sClass, const char *sFunction, const QString &sMsg)
Assert that the calling thread is the current holder of the AudioEngine lock.
float m_fFXPeak_R[MAX_FX]
void handleDriverChange()
The audio driver was changed what possible changed the tick size - which depends on both the sample r...
void reset(bool bWithJackBroadcast=true)
MidiInput * m_pMidiDriver
void updateSongTransportPosition(double fTick, long long nFrame, std::shared_ptr< TransportPosition > pPos)
long long computeTickInterval(double *fTickStart, double *fTickEnd, unsigned nIntervalLengthInFrames)
void startAudioDrivers()
Creation and initialization of all audio and MIDI drivers called in Hydrogen::Hydrogen().
void processAudio(uint32_t nFrames)
void incrementTransportPosition(uint32_t nFrames)
void updateNoteQueue(unsigned nIntervalLengthInFrames)
Takes all notes from the currently playing patterns, from the MIDI queue m_midiNoteQueue,...
static double computeDoubleTickSize(const int nSampleRate, const float fBpm, const int nResolution)
void raiseError(unsigned nErrorCode)
long long getRealtimeFrame() const
std::thread::id m_LockingThread
Thread ID of the current holder of the AudioEngine lock.
Base abstract class for audio output classes.
virtual unsigned getSampleRate()=0
virtual int init(unsigned nBufferSize)=0
float get_value(float x) const noexcept
Get value at given location.
static QString sPrintIndention
String used to format the debugging string output of some core classes.
static const char * _class_name()
return the class name
Driver for export audio to disk.
void set_peak_r(float val)
float get_out_L(int nBufferPos)
void set_peak_l(float val)
float get_out_R(int nBufferPos)
static Effects * get_instance()
Returns a pointer to the current Effects singleton stored in __instance.
static void create_instance()
If __instance equals 0, a new Effects singleton will be created and stored in it.
LadspaFX * getLadspaFX(int nFX) const
static EventQueue * get_instance()
Returns a pointer to the current EventQueue singleton stored in __instance.
void push_event(const EventType type, const int nValue)
Queues the next event into the EventQueue.
static QString click_file_path()
Returns a string containing the path to the click.wav file used in the metronome.
std::shared_ptr< Song > getSong() const
Get the current song.
Song::Mode getMode() const
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
MidiOutput * getMidiOutput() const
AudioEngine * getAudioEngine() const
@ UNKNOWN_DRIVER
The provided input in createDriver() does not match any of the choices for H2Core::Preferences::Audio...
@ ERROR_STARTING_DRIVER
Unable to connect the audio driver stored in H2Core::AudioEngine::m_pAudioDriver in audioEngine_start...
AudioOutput * getAudioOutput() const
Used to display audio driver info.
void clearPerTrackAudioBuffers(uint32_t nFrames)
Resets the buffers contained in m_pTrackOutputPortsL and m_pTrackOutputPortsR.
@ Listener
An external program is Timebase controller and Hydrogen will disregard all tempo markers on the Timel...
int getPluginType() const
void connectAudioPorts(float *pIn_L, float *pIn_R, float *pOut_L, float *pOut_R)
void processFX(unsigned nFrames)
virtual void handleQueueAllNoteOff()=0
A note plays an associated instrument with a velocity left and right pan.
int get_position() const
__position accessor
void set_length(int value)
__length setter
void swing()
Add swing contribution to __humanize_delay.
void set_humanize_delay(int value)
__humanize_delay setter
int get_humanize_delay() const
__humanize_delay accessor
void set_position(int value)
__position setter
std::shared_ptr< Instrument > get_instrument()
__instrument accessor
float get_lead_lag() const
__lead_lag accessor
float get_pitch() const
__pitch accessor
void humanize()
Add random contributions to __pitch, __humanize_delay, and __velocity.
void set_just_recorded(bool value)
__just_recorded setter
int get_length() const
__length accessor
float get_velocity() const
__velocity accessor
bool get_note_off() const
__note_off accessor
void computeNoteStart()
Calculates the m_nNoteStart in frames corresponding to the __position in ticks and storing the used t...
void set_velocity(float value)
__velocity setter
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
long long getNoteStart() const
void set_note_off(bool value)
__note_off setter
float get_probability() const
int get_instrument_id() const
__instrument_id accessor
PatternList is a collection of patterns.
Pattern class is a Note container.
int get_length() const
set the denominator of the pattern
const notes_t * get_notes() const
get the virtual pattern set
std::multimap< int, Note * > notes_t
< multimap note type
Manager for User Preferences File (singleton)
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
static std::vector< AudioDriver > getSupportedAudioDrivers()
static QString audioDriverToQString(const AudioDriver &driver)
QString m_sMidiDriver
MIDI driver.
AudioDriver m_audioDriver
Audio driver.
static std::shared_ptr< Sample > load(const QString &filepath, const License &license=License())
void process(uint32_t nFrames)
void handleTimelineOrTempoChange()
Recalculates all note starts to make them valid again after a TempoMarker was added to or deleted fro...
float * m_pMainOut_L
sampler main out (left channel)
float * m_pMainOut_R
sampler main out (right channel)
void handleSongSizeChange()
Recalculates all note starts and positions to make them valid again after the song size changed,...
static constexpr int nDefaultResolution
@ Finishing
Transport is still in loop mode (frames and ticks larger than song size are allowed) but playback end...
@ Stacked
An arbitrary number of pattern can be played.
@ Selected
Only one pattern - the one currently selected in the GUI - will be played back.
void process(uint32_t nFrames)
static long long computeFrameFromTick(double fTick, double *fTickMismatch, int nSampleRate=0)
Calculates frame equivalent of fTick.
static double computeTickFromFrame(long long nFrame, int nSampleRate=0)
Calculates tick equivalent of nFrame.
#define MAX_NOTES
Maximum number of notes.
#define MAX_FX
Maximum number of effects.
@ EVENT_RELOCATION
Triggered in case there is a relocation of the transport position while trasnsport is not rolling.
@ EVENT_METRONOME
Triggered when a metronome note is passed to the H2Core::Sampler.
@ EVENT_PLAYING_PATTERNS_CHANGED
The list of currently played patterns (AudioEngine::getPlayingPatterns()) did change.
@ EVENT_SONG_SIZE_CHANGED
@ EVENT_BBT_CHANGED
The coarse grained transport position in beats and bars did change.
timeval currentTime2()
Gets the current time.
bool operator()(Note *pNote1, Note *pNote2)