83 : m_pSampler( nullptr )
85 , m_pAudioDriver( nullptr )
86 , m_pMidiDriver( nullptr )
87 , m_pMidiDriverOut( nullptr )
88 , m_state(
State::Initialized )
89 , m_pMetronomeInstrument( nullptr )
90 , m_fSongSizeInTicks( 0 )
91 , m_nRealtimeFrame( 0 )
92 , m_fMasterPeak_L( 0.0f )
93 , m_fMasterPeak_R( 0.0f )
94 , m_nextState(
State::Ready )
95 , m_fProcessTime( 0.0f )
96 , m_fLadspaTime( 0.0f )
97 , m_fMaxProcessTime( 0.0f )
99 , m_pLocker({
nullptr, 0,
nullptr})
100 , m_fLastTickEnd( 0 )
101 , m_bLookaheadApplied(
false )
104 m_pTransportPosition = std::make_shared<TransportPosition>(
"Transport" );
105 m_pQueuingPosition = std::make_shared<TransportPosition>(
"Queuing" );
108 m_pSynth =
new Synth;
112 srand( time(
nullptr ) );
117 m_pMetronomeInstrument = std::make_shared<Instrument>(
METRONOME_INSTR_ID,
"metronome" );
119 auto pLayer = std::make_shared<InstrumentLayer>(
Sample::load( sMetronomeFilename ) );
120 auto pCompo = std::make_shared<InstrumentComponent>( 0 );
121 pCompo->set_layer(pLayer, 0);
122 m_pMetronomeInstrument->get_components()->push_back( pCompo );
123 m_pMetronomeInstrument->set_is_metronome_instrument(
true);
124 m_pMetronomeInstrument->set_volume(
127 m_AudioProcessCallback = &audioEngine_process;
135 #ifdef H2CORE_HAVE_PORTAUDIO
136 m_supportedAudioDrivers <<
"PortAudio";
138 if ( m_bJackSupported ) {
139 m_supportedAudioDrivers <<
"JACK";
141#elif defined(__APPLE__)
142 #ifdef H2CORE_HAVE_COREAUDIO
143 m_supportedAudioDrivers <<
"CoreAudio";
145 if ( m_bJackSupported ) {
146 m_supportedAudioDrivers <<
"JACK";
148 #ifdef H2CORE_HAVE_PULSEAUDIO
149 m_supportedAudioDrivers <<
"PulseAudio";
151 #ifdef H2CORE_HAVE_PORTAUDIO
152 m_supportedAudioDrivers <<
"PortAudio";
155 if ( m_bJackSupported ) {
156 m_supportedAudioDrivers <<
"JACK";
158 #ifdef H2CORE_HAVE_PULSEAUDIO
159 m_supportedAudioDrivers <<
"PulseAudio";
161 #ifdef H2CORE_HAVE_ALSA
162 m_supportedAudioDrivers <<
"ALSA";
164 #ifdef H2CORE_HAVE_OSS
165 m_supportedAudioDrivers <<
"OSS";
167 #ifdef H2CORE_HAVE_PORTAUDIO
168 m_supportedAudioDrivers <<
"PortAudio";
172#ifdef H2CORE_HAVE_LADSPA
181 ERRORLOG(
"Error the audio engine is not in State::Initialized" );
187 INFOLOG(
"*** Hydrogen audio engine shutdown ***" );
202#ifdef H2CORE_HAVE_LADSPA
224 #ifdef H2CORE_HAVE_DEBUG
227 QString(
"by %1 : %2 : %3" ).arg( function ).arg( line ).arg( file ) );
240 #ifdef H2CORE_HAVE_DEBUG
243 QString(
"by %1 : %2 : %3" ).arg( function ).arg( line ).arg( file ) );
255 #ifdef H2CORE_HAVE_DEBUG
265 #ifdef H2CORE_HAVE_DEBUG
268 QString(
"by %1 : %2 : %3" ).arg( function ).arg( line ).arg( file ) );
274 WARNINGLOG( QString(
"Lock timeout: lock timeout %1:%2:%3, lock held by %4:%5:%6" )
275 .arg( file ).arg( function ).arg( line )
284 #ifdef H2CORE_HAVE_DEBUG
297 #ifdef H2CORE_HAVE_DEBUG
309 ERRORLOG(
"Error the audio engine is not in State::Ready" );
323 ERRORLOG( QString(
"Error the audio engine is not in State::Playing but [%1]" )
324 .arg(
static_cast<int>(
getState() ) ) );
339#ifdef H2CORE_HAVE_LADSPA
340 for (
int ii = 0; ii <
MAX_FX; ++ii ) {
361#ifdef H2CORE_HAVE_JACK
362 if ( pHydrogen->hasJackTransport() && bWithJackBroadcast ) {
372 float fTickSize = nSampleRate * 60.0 / fBpm / nResolution;
379 double fTickSize =
static_cast<double>(nSampleRate) * 60.0 /
380 static_cast<double>(fBpm) /
381 static_cast<double>(nResolution);
389 const auto pDriver = pHydrogen->getAudioOutput();
391 if ( pDriver ==
nullptr || pDriver->getSampleRate() == 0 ) {
397 static_cast<float>(pDriver->getSampleRate());
405#ifdef H2CORE_HAVE_JACK
410 if ( pHydrogen->hasJackTransport() && bWithJackBroadcast ) {
411 double fTickMismatch;
413 fTick, &fTickMismatch );
443 if ( std::fmod( fNewTick, std::floor( fNewTick ) ) >= 0.97 ) {
444 INFOLOG( QString(
"Computed tick [%1] will be rounded to [%2] in order to avoid glitches" )
445 .arg( fNewTick, 0,
'E', -1 ).arg( std::round( fNewTick ) ) );
446 fNewTick = std::round( fNewTick );
486 if ( pSong ==
nullptr ) {
525 const auto pSong = pHydrogen->getSong();
546 bool bBBTChanged =
false;
547 const int nBar = std::max( pPos->getColumn(), 0 ) + 1;
548 if ( nBar != pPos->getBar() ) {
549 pPos->setBar( nBar );
553 const int nBeat =
static_cast<int>(
554 std::floor(
static_cast<float>(pPos->getPatternTickPosition()) / 48 )) + 1;
555 if ( pPos->getBeat() != nBeat ) {
556 pPos->setBeat( nBeat );
576 pPos->setTick( fTick );
577 pPos->setFrame( nFrame );
579 const double fPatternStartTick =
580 static_cast<double>(pPos->getPatternStartTick());
581 const int nPatternSize = pPos->getPatternSize();
583 if ( fTick >= fPatternStartTick +
static_cast<double>(nPatternSize) ||
584 fTick < fPatternStartTick ) {
587 pPos->setPatternStartTick( pPos->getPatternStartTick() +
588 static_cast<long>(std::floor( ( fTick - fPatternStartTick ) /
589 static_cast<double>(nPatternSize) )) *
603 long nPatternTickPosition =
static_cast<long>(std::floor( fTick )) -
604 pPos->getPatternStartTick();
605 if ( nPatternTickPosition > nPatternSize ) {
606 nPatternTickPosition = (
static_cast<long>(std::floor( fTick ))
607 - pPos->getPatternStartTick() ) %
610 pPos->setPatternTickPosition( nPatternTickPosition );
622 const auto pSong = pHydrogen->getSong();
624 pPos->setTick( fTick );
625 pPos->setFrame( nFrame );
628 ERRORLOG( QString(
"[%1] Provided tick [%2] is negative!" )
629 .arg( pPos->getLabel() )
630 .arg( fTick, 0,
'f' ) );
635 if ( pSong->getPatternGroupVector()->size() == 0 ) {
637 pPos->setPatternStartTick( 0 );
638 pPos->setPatternTickPosition( 0 );
642 long nPatternStartTick;
643 nNewColumn = pHydrogen->getColumnForTick(
644 std::floor( fTick ), pSong->isLoopEnabled(), &nPatternStartTick );
645 pPos->setPatternStartTick( nPatternStartTick );
651 pPos->setPatternTickPosition(
652 std::fmod( std::floor( fTick ) - nPatternStartTick,
656 pPos->setPatternTickPosition( std::floor( fTick ) - nPatternStartTick );
660 if ( pPos->getColumn() != nNewColumn ) {
661 pPos->setColumn( nNewColumn );
684 auto pSong = pHydrogen->getSong();
686 const float fOldBpm = pPos->getBpm();
689 if ( fNewBpm != fOldBpm ) {
690 pPos->setBpm( fNewBpm );
694 const float fOldTickSize = pPos->getTickSize();
695 const float fNewTickSize =
697 fNewBpm, pSong->getResolution() );
699#if defined(WIN32) and !defined(WIN64)
705 if ( std::abs( fNewTickSize - fOldTickSize ) < 1e-2 ) {
707 if ( fNewTickSize == fOldTickSize ) {
712 if ( fNewTickSize == 0 ) {
713 ERRORLOG( QString(
"[%1] Something went wrong while calculating the tick size. [oldTS: %2, newTS: %3]" )
714 .arg( pPos->getLabel() )
715 .arg( fOldTickSize, 0,
'f' ).arg( fNewTickSize, 0,
'f' ) );
723 pPos->setLastLeadLagFactor( 0 );
735 pPos->setTickSize( fNewTickSize );
745 const long long nNewFrame =
747 &pPos->m_fTickMismatch );
748 pPos->setFrameOffsetTempo( nNewFrame - pPos->getFrame() +
749 pPos->getFrameOffsetTempo() );
753 const long long nNewLookahead =
757 nNewFrame + nNewLookahead ) + pPos->getTickMismatch();
777 if ( pPos->getFrame() != nNewFrame ) {
778 pPos->setFrame( nNewFrame );
787 float *pBuffer_L, *pBuffer_R;
793 assert( pBuffer_L !=
nullptr && pBuffer_R !=
nullptr );
794 memset( pBuffer_L, 0, nFrames *
sizeof(
float ) );
795 memset( pBuffer_R, 0, nFrames *
sizeof(
float ) );
798#ifdef H2CORE_HAVE_JACK
802 if ( pJackAudioDriver !=
nullptr ) {
810#ifdef H2CORE_HAVE_LADSPA
815 for (
unsigned i = 0; i <
MAX_FX; ++i ) {
817 if ( pFX !=
nullptr ) {
820 memset( pFX->
m_pBuffer_L, 0, nFrames *
sizeof(
float ) );
821 memset( pFX->
m_pBuffer_R, 0, nFrames *
sizeof(
float ) );
830 INFOLOG( QString(
"Creating driver [%1]" ).arg( sDriver ) );
834 auto pSong = pHydrogen->getSong();
837 if ( sDriver ==
"OSS" ) {
839 }
else if ( sDriver ==
"JACK" ) {
841#ifdef H2CORE_HAVE_JACK
842 if (
auto pJackDriver =
dynamic_cast<JackAudioDriver*
>( pAudioDriver ) ) {
843 pJackDriver->setConnectDefaults(
849 else if ( sDriver ==
"ALSA" ) {
852 else if ( sDriver ==
"PortAudio" ) {
855 else if ( sDriver ==
"CoreAudio" ) {
858 else if ( sDriver ==
"PulseAudio" ) {
861 else if ( sDriver ==
"Fake" ) {
862 WARNINGLOG(
"*** Using FAKE audio driver ***" );
865 else if ( sDriver ==
"DiskWriterDriver" ) {
868 else if ( sDriver ==
"NullDriver" ) {
872 ERRORLOG( QString(
"Unknown driver [%1]" ).arg( sDriver ) );
877 if ( pAudioDriver ==
nullptr ) {
878 INFOLOG( QString(
"Unable to create driver [%1]" ).arg( sDriver ) );
883 int nRes = pAudioDriver->
init( pPref->m_nBufferSize );
885 ERRORLOG( QString(
"Error code [%2] while initializing audio driver [%1]." )
886 .arg( sDriver ).arg( nRes ) );
898 if ( pSong !=
nullptr ) {
912 ERRORLOG( QString(
"Error code [%2] while connecting audio driver [%1]." )
913 .arg( sDriver ).arg( nRes ) );
927 if ( pSong !=
nullptr && pHydrogen->hasJackAudioDriver() ) {
928 pHydrogen->renameJackPorts( pSong );
933 if ( pSong !=
nullptr ) {
948 ERRORLOG( QString(
"Audio engine is not in State::Initialized but [%1]" )
949 .arg(
static_cast<int>(
getState() ) ) );
954 ERRORLOG(
"The audio driver is still alive" );
957 ERRORLOG(
"The MIDI driver is still active" );
962 if ( sAudioDriver !=
"Auto" ) {
975 ERRORLOG( QString(
"Couldn't start audio driver [%1], falling back to NullDriver" )
976 .arg( sAudioDriver ) );
984#ifdef H2CORE_HAVE_ALSA
992#ifdef H2CORE_HAVE_PORTMIDI
1000#ifdef H2CORE_HAVE_COREMIDI
1008#ifdef H2CORE_HAVE_JACK
1033 ERRORLOG( QString(
"Audio engine is not in State::Prepared or State::Ready but [%1]" )
1034 .arg(
static_cast<int>(
m_state) ) );
1094 auto pAudioEngine = pHydrogen->getAudioEngine();
1095 auto pSong = pHydrogen->getSong();
1097 if ( pSong ==
nullptr ) {
1102 float fBpm = pAudioEngine->getTransportPosition()->getBpm();
1109 const float fJackMasterBpm = pHydrogen->getMasterBpm();
1110 if ( ! std::isnan( fJackMasterBpm ) && fBpm != fJackMasterBpm ) {
1111 fBpm = fJackMasterBpm;
1115 else if ( pSong->getIsTimelineActivated() &&
1118 const float fTimelineBpm = pHydrogen->getTimeline()->getTempoAtColumn( nColumn );
1119 if ( fTimelineBpm != fBpm ) {
1121 fBpm = fTimelineBpm;
1127 if ( pAudioEngine->getNextBpm() != fBpm ) {
1130 fBpm = pAudioEngine->getNextBpm();
1139 std::shared_ptr<Song> pSong = pHydrogen->
getSong();
1140 if ( pSong ==
nullptr ) {
1144#ifdef H2CORE_HAVE_LADSPA
1145 for (
unsigned nFX = 0; nFX <
MAX_FX; ++nFX ) {
1147 if ( pFX ==
nullptr ) {
1168 const auto pSong = pHydrogen->getSong();
1170 if ( pHydrogen->isPatternEditorLocked() ) {
1174 int nPatternNumber = -1;
1177 if ( nColumn < (*pSong->getPatternGroupVector()).size() ) {
1179 const auto pPatternList = pSong->getPatternList();
1180 if ( pPatternList !=
nullptr ) {
1182 const auto pColumn = ( *pSong->getPatternGroupVector() )[ nColumn ];
1185 for (
const auto& pattern : *pColumn ) {
1186 nIndex = pPatternList->index( pattern );
1188 if ( nIndex > nPatternNumber ) {
1189 nPatternNumber = nIndex;
1195 pHydrogen->setSelectedPatternNumber( nPatternNumber,
true,
true );
1203 if ( pSong ==
nullptr ) {
1215 std::shared_ptr<Song> pSong = pHydrogen->
getSong();
1233 const long long nNoteStartInFrames = pNote->
getNoteStart();
1241 if ( nNoteStartInFrames < nFrame +
static_cast<long long>(nframes) ) {
1244 if ( fNoteProbability != 1. ) {
1246 if ( fNoteProbability < (
float) rand() / (
float) RAND_MAX ) {
1258 if ( pNoteInstrument->is_stop_notes() ){
1259 Note *pOffNote =
new Note( pNoteInstrument );
1280 const int nInstrument = pSong->getInstrumentList()->index( pNote->
get_instrument() );
1286 if ( nInstrument != -1 ) {
1337 if ( fSlackTime < 0.0 ) {
1348 if ( !pAudioEngine->
tryLockFor( std::chrono::microseconds( (
int)(1000.0*fSlackTime) ),
1350 ___ERRORLOG( QString(
"Failed to lock audioEngine in allowed %1 ms, missed buffer" ).arg( fSlackTime ) );
1367 std::shared_ptr<Song> pSong = pHydrogen->
getSong();
1368 if ( pSong ==
nullptr ) {
1376#ifdef H2CORE_HAVE_JACK
1379 if ( pAudioDriver ==
nullptr ) {
1380 ERRORLOG(
"AudioDriver is not ready!" );
1381 assert( pAudioDriver );
1408 static_cast<long long>(nframes) );
1429 pAudioEngine->
stop();
1431 pAudioEngine->
locate( 0 );
1456 ( finishTimeval.tv_sec - startTimeval.tv_sec ) * 1000.0
1457 + ( finishTimeval.tv_usec - startTimeval.tv_usec ) / 1000.0;
1466 ___WARNINGLOG( QString(
"Ladspa process time = %1" ).arg( fLadspaTime ) );
1487 assert( pBuffer_L !=
nullptr && pBuffer_R !=
nullptr );
1492 for (
unsigned i = 0; i < nFrames; ++i ) {
1493 pBuffer_L[ i ] += out_L[ i ];
1494 pBuffer_R[ i ] += out_R[ i ];
1500 for (
unsigned i = 0; i < nFrames; ++i ) {
1501 pBuffer_L[ i ] += out_L[ i ];
1502 pBuffer_R[ i ] += out_R[ i ];
1507#ifdef H2CORE_HAVE_LADSPA
1508 for (
unsigned nFX = 0; nFX <
MAX_FX; ++nFX ) {
1510 if ( ( pFX ) && ( pFX->
isEnabled() ) ) {
1513 float *buf_L, *buf_R;
1522 for (
unsigned i = 0; i < nFrames; ++i ) {
1523 pBuffer_L[ i ] += buf_L[ i ];
1524 pBuffer_R[ i ] += buf_R[ i ];
1538 ( ladspaTime_end.tv_sec - ladspaTime_start.tv_sec ) * 1000.0
1539 + ( ladspaTime_end.tv_usec - ladspaTime_start.tv_usec ) / 1000.0;
1542 for (
unsigned i = 0; i < nFrames; ++i ) {
1543 val_L = pBuffer_L[i];
1544 val_R = pBuffer_R[i];
1555 for (
auto component : *pSong->getComponents() ) {
1557 for (
unsigned i = 0; i < nFrames; ++i ) {
1558 float compo_val_L = pComponent->
get_out_L(i);
1559 float compo_val_R = pComponent->
get_out_R(i);
1561 if( compo_val_L > pComponent->
get_peak_l() ) {
1564 if( compo_val_R > pComponent->
get_peak_r() ) {
1580 WARNINGLOG( QString(
"Provided bpm %1 is too high. Assigning upper bound %2 instead" )
1581 .arg( fNextBpm ).arg(
MAX_BPM ) );
1583 else if ( fNextBpm <
MIN_BPM ) {
1585 WARNINGLOG( QString(
"Provided bpm %1 is too low. Assigning lower bound %2 instead" )
1586 .arg( fNextBpm ).arg(
MIN_BPM ) );
1596 INFOLOG( QString(
"Set song: %1" ).arg( pNewSong->getName() ) );
1601 ERRORLOG( QString(
"Error the audio engine is not in State::Prepared but [%1]" )
1602 .arg(
static_cast<int>(
getState() ) ) );
1615 pHydrogen->renameJackPorts( pNewSong );
1621 pHydrogen->setTimeline( pNewSong->getTimeline() );
1622 pHydrogen->getTimeline()->activate();
1639 ERRORLOG( QString(
"Error the audio engine is not in State::Ready but [%1]" )
1640 .arg(
static_cast<int>(
getState() ) ) );
1655 auto pSong = pHydrogen->getSong();
1657 if ( pSong ==
nullptr ) {
1662 auto updatePatternSize = []( std::shared_ptr<TransportPosition> pPos ) {
1663 if ( pPos->getPlayingPatterns()->size() > 0 ) {
1665 pPos->setPatternSize( pPos->getPlayingPatterns()->longest_pattern_length(
false ) );
1687 const double fNewSongSizeInTicks =
static_cast<double>( pSong->lengthInTicks() );
1691 const bool bEmptySong =
1694 double fNewStrippedTick, fRepetitions;
1723 auto endOfSongReached = [&](){
1742 if ( nOldColumn >= pSong->getPatternGroupVector()->size() &&
1750 const long nNewPatternStartTick = pHydrogen->getTickForColumn( nOldColumn );
1752 if ( nNewPatternStartTick == -1 &&
1770 static_cast<double>(nNewPatternStartTick -
1774#ifdef H2CORE_HAVE_DEBUG
1775 const long nNewPatternTickPosition =
1776 static_cast<long>(std::floor( fNewStrippedTick )) - nNewPatternStartTick;
1779 ERRORLOG( QString(
"[nPatternTickPosition mismatch] old: %1, new: %2" )
1781 .arg( nNewPatternTickPosition ) );
1786 const double fNewTick = fNewStrippedTick + fRepetitions * fNewSongSizeInTicks;
1801 fTickOffset = std::round( fTickOffset );
1802 fTickOffset *= 1e-8;
1833#if defined(WIN32) and !defined(WIN64)
1859#ifdef H2CORE_HAVE_DEBUG
1862 ERRORLOG( QString(
"[nColumn mismatch] old: %1, new: %2" )
1887 auto removePattern = [&]( std::shared_ptr<TransportPosition> pPos ) {
1888 auto pPlayingPatterns = pPos->getPlayingPatterns();
1890 for (
int ii = 0; ii < pPlayingPatterns->size(); ++ii ) {
1891 if ( pPlayingPatterns->get( ii ) == pPattern ) {
1892 pPlayingPatterns->del( ii );
1909 auto pSong = pHydrogen->getSong();
1910 auto pPlayingPatterns = pPos->getPlayingPatterns();
1916 const auto nPrevPatternNumber = pPlayingPatterns->size();
1918 pPlayingPatterns->clear();
1920 if ( pSong->getPatternGroupVector()->size() == 0 ) {
1922 if ( nPrevPatternNumber > 0 ) {
1928 auto nColumn = std::max( pPos->getColumn(), 0 );
1929 if ( nColumn >= pSong->getPatternGroupVector()->size() ) {
1930 ERRORLOG( QString(
"Provided column [%1] exceeds allowed range [0,%2]. Using 0 as fallback." )
1931 .arg( nColumn ).arg( pSong->getPatternGroupVector()->size() - 1 ) );
1935 for (
const auto& ppattern : *( *( pSong->getPatternGroupVector() ) )[ nColumn ] ) {
1936 if ( ppattern !=
nullptr ) {
1937 pPlayingPatterns->add( ppattern,
true );
1946 ( nPrevPatternNumber != 0 || pPlayingPatterns->size() != 0 ) ) {
1952 auto pSelectedPattern =
1953 pSong->getPatternList()->get( pHydrogen->getSelectedPatternNumber() );
1955 if ( pSelectedPattern !=
nullptr &&
1956 ! ( pPlayingPatterns->size() == 1 &&
1957 pPlayingPatterns->get( 0 ) == pSelectedPattern ) ) {
1958 pPlayingPatterns->clear();
1959 pPlayingPatterns->add( pSelectedPattern,
true );
1970 auto pNextPatterns = pPos->getNextPatterns();
1972 if ( pNextPatterns->size() > 0 ) {
1973 for (
const auto& ppattern : *pNextPatterns ) {
1974 if ( ppattern ==
nullptr ) {
1978 if ( ( pPlayingPatterns->del( ppattern ) ) == nullptr ) {
1981 pPlayingPatterns->add( ppattern,
true );
1985 ppattern->removeFlattenedVirtualPatterns( pPlayingPatterns );
1994 pNextPatterns->clear();
1998 if ( pPlayingPatterns->size() > 0 ) {
2000 pPos->setPatternSize( pPlayingPatterns->longest_pattern_length(
false ) );
2011 auto pSong = pHydrogen->getSong();
2012 auto pPatternList = pSong->getPatternList();
2013 auto pPattern = pPatternList->get( nPatternNumber );
2014 if ( pPattern ==
nullptr ) {
2033 auto pSong = pHydrogen->getSong();
2034 auto pPatternList = pSong->getPatternList();
2036 bool bAlreadyPlaying =
false;
2041 auto pRequestedPattern = pPatternList->get( nPatternNumber );
2043 auto flushAndAddNext = [&]( std::shared_ptr<TransportPosition> pPos ) {
2045 auto pNextPatterns = pPos->getNextPatterns();
2046 auto pPlayingPatterns = pPos->getPlayingPatterns();
2048 pNextPatterns->clear();
2049 for (
int ii = 0; ii < pPlayingPatterns->size(); ++ii ) {
2051 auto pPlayingPattern = pPlayingPatterns->get( ii );
2052 if ( pPlayingPattern != pRequestedPattern ) {
2053 pNextPatterns->add( pPlayingPattern );
2055 else if ( pRequestedPattern !=
nullptr ) {
2056 bAlreadyPlaying =
true;
2061 if ( ! bAlreadyPlaying && pRequestedPattern !=
nullptr ) {
2062 pNextPatterns->add( pRequestedPattern );
2073 auto copyPlayingPatterns = [&]( std::shared_ptr<TransportPosition> pPos ) {
2074 auto pPlayingPatterns = pPos->getPlayingPatterns();
2075 auto pNextPatterns = pPos->getNextPatterns();
2077 for (
const auto& ppPattern : *pPlayingPatterns ) {
2078 pNextPatterns->add( ppPattern );
2102#if defined(WIN32) and !defined(WIN64)
2128 std::vector<Note*> notes;
2133 if ( notes.size() > 0 ) {
2134 for (
auto nnote : notes ) {
2135 nnote->computeNoteStart();
2146 if ( notes.size() > 0 ) {
2147 for (
auto nnote : notes ) {
2148 nnote->computeNoteStart();
2160 std::vector<Note*> notes;
2165 const long nTickOffset =
2168 if ( notes.size() > 0 ) {
2169 for (
auto nnote : notes ) {
2179 nnote->set_position( std::max( nnote->get_position() + nTickOffset,
2180 static_cast<long>(0) ) );
2181 nnote->computeNoteStart();
2192 if ( notes.size() > 0 ) {
2193 for (
auto nnote : notes ) {
2203 nnote->set_position( std::max( nnote->get_position() + nTickOffset,
2204 static_cast<long>(0) ) );
2205 nnote->computeNoteStart();
2217 const auto pTimeline = pHydrogen->getTimeline();
2220 long long nFrameStart, nFrameEnd;
2233 nFrameStart = pPos->getFrame();
2255 if ( pPos->getLastLeadLagFactor() != 0 ) {
2256 if ( pPos->getLastLeadLagFactor() != nLeadLagFactor ) {
2257 nLeadLagFactor = pPos->getLastLeadLagFactor();
2260 pPos->setLastLeadLagFactor( nLeadLagFactor );
2263 const long long nLookahead = nLeadLagFactor +
2266 nFrameEnd = nFrameStart + nLookahead +
2267 static_cast<long long>(nIntervalLengthInFrames);
2274 nFrameStart += nLookahead;
2278 pPos->getTickMismatch() ) - pPos->getTickOffsetQueuing() ;
2280 pPos->getTickOffsetQueuing();
2297 return nLeadLagFactor;
2310 if ( std::ceil( fTick ) - fTick > 0 &&
2311 std::ceil( fTick ) - fTick < 1E-6 ) {
2312 return std::floor( fTick ) + 1;
2315 return std::floor( fTick );
2322 std::shared_ptr<Song> pSong = pHydrogen->
getSong();
2324 double fTickStartComp, fTickEndComp;
2326 long long nLeadLagFactor =
2348 AutomationPath* pAutomationPath = pSong->getVelocityAutomationPath();
2358 const long nTickStart =
static_cast<long>(
coarseGrainTick( fTickStartComp ));
2359 const long nTickEnd =
static_cast<long>(
coarseGrainTick( fTickEndComp ));
2376 for (
long nnTick = nTickStart; nnTick < nTickEnd; ++nnTick ) {
2386 static_cast<double>(nnTick),
2399 static_cast<double>(nnTick),
2408 int nMetronomeTickPosition;
2409 if ( pSong->getPatternGroupVector()->size() == 0 ) {
2410 nMetronomeTickPosition = nnTick;
2415 if ( nMetronomeTickPosition % 48 == 0 ) {
2422 if ( nMetronomeTickPosition == 0 ) {
2446 pSong->getPatternGroupVector()->size() == 0 ) {
2465 if ( pPlayingPatterns->size() != 0 ) {
2466 for (
auto nPat = 0; nPat < pPlayingPatterns->size(); ++nPat ) {
2467 Pattern *pPattern = pPlayingPatterns->get( nPat );
2468 assert( pPattern !=
nullptr );
2477 Note *pNote = it->second;
2478 if ( pNote !=
nullptr ) {
2481 Note *pCopiedNote =
new Note( pNote );
2492 static_cast<float>(nLeadLagFactor) ));
2508 pCopiedNote->
swing();
2527 static_cast<long>(pCopiedNote->
get_length()),
2552 ERRORLOG( QString(
"Error the audio engine is not in State::Ready, State::Playing, or State::Testing but [%1]" )
2553 .arg(
static_cast<int>(
getState() ) ) );
2569#ifdef H2CORE_HAVE_JACK
2588#ifdef H2CORE_HAVE_JACK
2606 const long long nFrameStart =
2608 const long long nFrameEnd =
2617 return nFrameEnd - nFrameStart;
2635#ifdef H2CORE_HAVE_JACK
2636 #ifdef H2CORE_HAVE_DYNAMIC_JACK_CHECK
2648 INFOLOG(
"JACK support enabled." );
2651 INFOLOG(
"Dynamic JACK support skipped. JACK support enabled." );
2659 INFOLOG(
"Hydrogen was compiled without JACK support." );
2670 sOutput = QString(
"%1[AudioEngine]\n" ).arg( sPrefix )
2671 .append(
"%1%2m_pTransportPosition:\n").arg( sPrefix ).arg( s );
2673 sOutput.append( QString(
"%1" )
2676 sOutput.append( QString(
"nullptr\n" ) );
2678 sOutput.append( QString(
"%1%2m_pQueuingPosition:\n").arg( sPrefix ).arg( s ) );
2680 sOutput.append( QString(
"%1" )
2683 sOutput.append( QString(
"nullptr\n" ) );
2685 sOutput.append( QString(
"%1%2m_fNextBpm: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fNextBpm, 0,
'f' ) )
2686 .append( QString(
"%1%2m_state: %3\n" ).arg( sPrefix ).arg( s ).arg(
static_cast<int>(
m_state) ) )
2687 .append( QString(
"%1%2m_nextState: %3\n" ).arg( sPrefix ).arg( s ).arg(
static_cast<int>(
m_nextState) ) )
2688 .append( QString(
"%1%2m_fSongSizeInTicks: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fSongSizeInTicks, 0,
'f' ) )
2689 .append( QString(
"%1%2m_fLastTickEnd: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fLastTickEnd, 0,
'f' ) )
2690 .append( QString(
"%1%2m_bLookaheadApplied: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_bLookaheadApplied ) )
2691 .append( QString(
"%1%2m_pSampler: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2692 .append( QString(
"%1%2m_pSynth: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2693 .append( QString(
"%1%2m_pAudioDriver: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2694 .append( QString(
"%1%2m_pMidiDriver: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2695 .append( QString(
"%1%2m_pMidiDriverOut: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2696 .append( QString(
"%1%2m_pEventQueue: stringification not implemented\n" ).arg( sPrefix ).arg( s ) );
2697#ifdef H2CORE_HAVE_LADSPA
2698 sOutput.append( QString(
"%1%2m_fFXPeak_L: [" ).arg( sPrefix ).arg( s ) );
2700 sOutput.append( QString(
" %1" ).arg( ii ) );
2702 sOutput.append( QString(
"]\n%1%2m_fFXPeak_R: [" ).arg( sPrefix ).arg( s ) );
2704 sOutput.append( QString(
" %1" ).arg( ii ) );
2706 sOutput.append( QString(
" ]\n" ) );
2708 sOutput.append( QString(
"%1%2m_fMasterPeak_L: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fMasterPeak_L ) )
2709 .append( QString(
"%1%2m_fMasterPeak_R: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fMasterPeak_R ) )
2710 .append( QString(
"%1%2m_fProcessTime: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fProcessTime ) )
2711 .append( QString(
"%1%2m_fMaxProcessTime: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fMaxProcessTime ) )
2712 .append( QString(
"%1%2m_fLadspaTime: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fLadspaTime ) )
2713 .append( QString(
"%1%2m_nRealtimeFrame: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_nRealtimeFrame ) )
2714 .append( QString(
"%1%2m_AudioProcessCallback: stringification not implemented\n" ).arg( sPrefix ).arg( s ) )
2715 .append( QString(
"%1%2m_songNoteQueue: length = %3\n" ).arg( sPrefix ).arg( s ).arg(
m_songNoteQueue.size() ) );
2716 sOutput.append( QString(
"%1%2m_midiNoteQueue: [\n" ).arg( sPrefix ).arg( s ) );
2718 sOutput.append( nn->toQString( sPrefix + s, bShort ) );
2720 sOutput.append( QString(
"]\n%1%2m_pMetronomeInstrument: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_pMetronomeInstrument->toQString( sPrefix + s, bShort ) ) )
2728 sOutput = QString(
"%1[AudioEngine]" ).arg( sPrefix )
2729 .append(
", m_pTransportPosition:\n");
2731 sOutput.append( QString(
"%1" )
2734 sOutput.append( QString(
"nullptr\n" ) );
2736 sOutput.append(
", m_pQueuingPosition:\n");
2738 sOutput.append( QString(
"%1" )
2741 sOutput.append( QString(
"nullptr\n" ) );
2743 sOutput.append( QString(
", m_fNextBpm: %1" ).arg(
m_fNextBpm, 0,
'f' ) )
2744 .append( QString(
", m_state: %1" ).arg(
static_cast<int>(
m_state) ) )
2745 .append( QString(
", m_nextState: %1" ).arg(
static_cast<int>(
m_nextState) ) )
2747 .append( QString(
", m_fLastTickEnd: %1" ).arg(
m_fLastTickEnd, 0,
'f' ) )
2749 .append( QString(
", m_pSampler: ..." ) )
2750 .append( QString(
", m_pSynth: ..." ) )
2751 .append( QString(
", m_pAudioDriver: ..." ) )
2752 .append( QString(
", m_pMidiDriver: ..." ) )
2753 .append( QString(
", m_pMidiDriverOut: ..." ) )
2754 .append( QString(
", m_pEventQueue: ..." ) );
2755#ifdef H2CORE_HAVE_LADSPA
2756 sOutput.append( QString(
", m_fFXPeak_L: [" ) );
2758 sOutput.append( QString(
" %1" ).arg( ii ) );
2760 sOutput.append( QString(
"], m_fFXPeak_R: [" ) );
2762 sOutput.append( QString(
" %1" ).arg( ii ) );
2764 sOutput.append( QString(
" ]" ) );
2766 sOutput.append( QString(
", m_fMasterPeak_L: %1" ).arg(
m_fMasterPeak_L ) )
2768 .append( QString(
", m_fProcessTime: %1" ).arg(
m_fProcessTime ) )
2770 .append( QString(
", m_fLadspaTime: %1" ).arg(
m_fLadspaTime ) )
2772 .append( QString(
", m_AudioProcessCallback: ..." ) )
2773 .append( QString(
", m_songNoteQueue: length = %1" ).arg(
m_songNoteQueue.size() ) );
2774 sOutput.append( QString(
", m_midiNoteQueue: [" ) );
2776 sOutput.append( nn->toQString( sPrefix + s, bShort ) );
2778 sOutput.append( QString(
"], m_pMetronomeInstrument: id = %1" ).arg(
m_pMetronomeInstrument->get_id() ) )
2791 if ( m_bNeedsLock ) {
#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
Assert that the AudioEngine lock is held if needed.
The audio engine deals with two distinct #TransportPosition.
int m_nLoopsDone
Indicates how many loops the transport already did when the user presses the Loop button again.
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...
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.
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)
AudioOutput * createAudioDriver(const QString &sDriver)
Create an audio driver using audioEngine_process() as its argument based on the provided choice and c...
void checkJackSupport()
Attempts to dynamically load the JACK 2 shared library and stores the result in m_bJackSupported.
friend void JackAudioDriver::updateTransportPosition()
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.
const QStringList getSupportedAudioDrivers() const
State getNextState() const
bool m_bJackSupported
Whether or not the shared library of the JACK server could be found on the system at runtime.
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.
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.
void assertLocked()
Assert that the calling thread is the current holder of the AudioEngine lock.
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.
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
virtual void disconnect()=0
virtual float * getOut_L()=0
virtual float * getOut_R()=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 string in createDriver() does not match any of the choices for Preferences::m_sAud...
@ 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.
JACK (Jack Audio Connection Kit) server driver.
void clearPerTrackAudioBuffers(uint32_t nFrames)
Resets the buffers contained in m_pTrackOutputPortsL and m_pTrackOutputPortsR.
@ Slave
An external program is timebase master and Hydrogen will disregard all tempo markers on the Timeline ...
static bool checkSupport()
Attempts to call several JACK executables in order to check for existing JACK support.
int getPluginType() const
void connectAudioPorts(float *pIn_L, float *pIn_R, float *pOut_L, float *pOut_R)
void processFX(unsigned nFrames)
void log(unsigned level, const QString &class_name, const char *func_name, const QString &msg)
the log function
bool should_log(unsigned lvl) const
return true if the level is set in the bitmask
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
long long getNoteStart() const
void set_note_off(bool value)
__note_off setter
float get_probability() const
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.
QString m_sAudioDriver
Audio driver.
QString m_sMidiDriver
MIDI 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 noteOn(Note *pNote)
Start playing a note.
void stopPlayingNotes(std::shared_ptr< Instrument > pInstr=nullptr)
void handleSongSizeChange()
Recalculates all note starts and positions to make them valid again after the song size changed,...
@ 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)