64 if ( pSong ==
nullptr ) {
69 pSong->setVolume( fMasterVolumeValue );
79 if ( pInstr !=
nullptr ) {
81 pInstr->set_volume( fVolumeValue );
84 pHydrogen->setSelectedInstrumentNumber( nStrip );
87 pHydrogen->setIsModified(
true );
105 auto pSong = pHydrogen->getSong();
107 if ( pSong ==
nullptr ) {
112 pSong->setIsMuted( bIsMuted );
114 pHydrogen->setIsModified(
true );
122 if ( pInstr ==
nullptr ) {
133 if ( pInstr !=
nullptr ) {
134 pInstr->set_muted( bIsMuted );
138 pHydrogen->setIsModified(
true );
149 if ( pInstr ==
nullptr ) {
160 if ( pInstr !=
nullptr ) {
162 pInstr->set_soloed( isSoloed );
166 pHydrogen->setIsModified(
true );
178 if ( pInstr !=
nullptr ) {
180 pInstr->setPanWithRangeFrom0To1( fValue );
184 pHydrogen->setIsModified(
true );
186 if ( bSelectStrip ) {
187 pHydrogen->setSelectedInstrumentNumber( nStrip );
201 if ( pInstr !=
nullptr ) {
203 pInstr->setPan( fValue );
207 pHydrogen->setIsModified(
true );
209 if ( bSelectStrip ) {
210 pHydrogen->setSelectedInstrumentNumber( nStrip );
221 if ( pSong ==
nullptr ) {
226 float fMasterVolume = pSong->getVolume();
228#ifdef H2CORE_HAVE_OSC
231 std::shared_ptr<Action> pFeedbackAction =
232 std::make_shared<Action>(
"MASTER_VOLUME_ABSOLUTE" );
234 pFeedbackAction->setValue( QString(
"%1")
235 .arg( fMasterVolume ) );
250 if ( pInstr !=
nullptr ) {
252 float fStripVolume = pInstr->get_volume();
254#ifdef H2CORE_HAVE_OSC
257 std::shared_ptr<Action> pFeedbackAction =
258 std::make_shared<Action>(
"STRIP_VOLUME_ABSOLUTE" );
260 pFeedbackAction->setParameter1( QString(
"%1").arg( nStrip + 1 ) );
261 pFeedbackAction->setValue( QString(
"%1").arg( fStripVolume ) );
269 QString(
"%1").arg( nStrip ) );
280#ifdef H2CORE_HAVE_OSC
281 if ( pPref->getOscFeedbackEnabled() ) {
282 std::shared_ptr<Action> pFeedbackAction =
283 std::make_shared<Action>(
"TOGGLE_METRONOME" );
285 pFeedbackAction->setParameter1( QString(
"%1")
286 .arg(
static_cast<int>(pPref->m_bUseMetronome) ) );
296 static_cast<int>(pPref->m_bUseMetronome) * 127 );
301 if ( pSong ==
nullptr ) {
306#ifdef H2CORE_HAVE_OSC
308 std::shared_ptr<Action> pFeedbackAction =
309 std::make_shared<Action>(
"MUTE_TOGGLE" );
311 pFeedbackAction->setParameter1( QString(
"%1")
312 .arg(
static_cast<int>(pSong->getIsMuted()) ) );
322 static_cast<int>(pSong->getIsMuted()) * 127 );
327 if ( pInstr !=
nullptr ) {
329#ifdef H2CORE_HAVE_OSC
331 std::shared_ptr<Action> pFeedbackAction =
332 std::make_shared<Action>(
"STRIP_MUTE_TOGGLE" );
334 pFeedbackAction->setParameter1( QString(
"%1").arg( nStrip + 1 ) );
335 pFeedbackAction->setValue( QString(
"%1")
336 .arg(
static_cast<int>(pInstr->is_muted()) ) );
344 QString(
"%1").arg( nStrip ) );
347 static_cast<int>(pInstr->is_muted()) * 127 );
355 if ( pInstr !=
nullptr ) {
357#ifdef H2CORE_HAVE_OSC
359 std::shared_ptr<Action> pFeedbackAction =
360 std::make_shared<Action>(
"STRIP_SOLO_TOGGLE" );
362 pFeedbackAction->setParameter1( QString(
"%1").arg( nStrip + 1 ) );
363 pFeedbackAction->setValue( QString(
"%1")
364 .arg(
static_cast<int>(pInstr->is_soloed()) ) );
371 QString(
"%1").arg( nStrip ) );
374 static_cast<int>(pInstr->is_soloed()) * 127 );
382 if ( pInstr !=
nullptr ) {
384#ifdef H2CORE_HAVE_OSC
386 std::shared_ptr<Action> pFeedbackAction =
387 std::make_shared<Action>(
"PAN_ABSOLUTE" );
389 pFeedbackAction->setParameter1( QString(
"%1").arg( nStrip + 1 ) );
390 pFeedbackAction->setValue( QString(
"%1")
391 .arg( pInstr->getPanWithRangeFrom0To1() ) );
398 QString(
"%1").arg( nStrip ) );
401 pInstr->getPanWithRangeFrom0To1() * 127 );
413 if ( pHydrogen->
getSong() ==
nullptr ) {
418 for (
auto param : params ) {
419 if ( pMidiDriver !=
nullptr &&
430 if ( pSong ==
nullptr ) {
435 auto pInstr = pSong->getInstrumentList()->get( nStrip );
436 if ( pInstr ==
nullptr ) {
437 ERRORLOG( QString(
"Couldn't find instrument [%1]" ).arg( nStrip ) );
451 auto pSong = pHydrogen->getSong();
453 if ( pSong ==
nullptr ) {
461 auto pInstrList = pSong->getInstrumentList();
462 for (
int ii = 0; ii < pInstrList->size(); ii++){
463 auto pInstr = pInstrList->get( ii );
464 if ( pInstr !=
nullptr ) {
499 pHydrogen->sequencer_stop();
512 if ( pHydrogen->isUnderSessionManagement() ) {
513 pHydrogen->restartDrivers();
516 pHydrogen->setSessionDrumkitNeedsRelinking(
true );
519 pSong->setFilename( sSongPath );
521 pHydrogen->setSong( pSong );
536 pHydrogen->sequencer_stop();
545 std::shared_ptr<Song> pSong;
546 if ( ! sRecoverSongPath.isEmpty() ) {
549 if ( pSong !=
nullptr ) {
550 pSong->setFilename( sSongPath );
556 if ( pSong ==
nullptr ) {
557 ERRORLOG( QString(
"Unable to open song [%1]." )
572 pHydrogen->sequencer_stop();
575 if ( pSong ==
nullptr ) {
576 ERRORLOG( QString(
"Unable to open song." ) );
580 return setSong( pSong, bRelinking );
588 pHydrogen->setSong( pSong, bRelinking );
590 if ( pHydrogen->isUnderSessionManagement() ) {
591 pHydrogen->restartDrivers();
607 pHydrogen->setIsModified(
false );
615 auto pSong = pHydrogen->getSong();
617 if ( pSong ==
nullptr ) {
623 QString sSongPath = pSong->getFilename();
625 if ( sSongPath.isEmpty() ) {
626 ERRORLOG(
"Unable to save song. Empty filename!" );
630#ifdef H2CORE_HAVE_OSC
631 if ( pHydrogen->isUnderSessionManagement() &&
632 pHydrogen->getSessionDrumkitNeedsRelinking() &&
633 ! pHydrogen->getSessionIsExported() ) {
638 QString sSessionDrumkitPath = pSong->getLastLoadedDrumkitPath();
640 auto drumkitDatabase = pHydrogen->getSoundLibraryDatabase()->getDrumkitDatabase();
641 if ( drumkitDatabase.find( sSessionDrumkitPath ) != drumkitDatabase.end() ) {
647 pHydrogen->getSoundLibraryDatabase()->updateDrumkit( sSessionDrumkitPath );
653 bool bSaved = pSong->save( sSongPath );
655 ERRORLOG( QString(
"Current song [%1] could not be saved!" )
671 auto pSong = pHydrogen->getSong();
673 if ( pSong ==
nullptr ) {
684 QString sPreviousFilename( pSong->getFilename() );
685 pSong->setFilename( sNewFilename );
695 if ( ! pHydrogen->isUnderSessionManagement() ) {
720 ERRORLOG( QString(
"Error: Closing the application via the core part is not supported yet!" ) );
731 if ( pHydrogen->getSong() ==
nullptr ) {
736 pHydrogen->setIsTimelineActivated( bActivate );
739 WARNINGLOG( QString(
"Timeline usage was [%1] in the Preferences. But these changes won't have an effect as long as there is still an external JACK timebase master." )
740 .arg( bActivate ?
"enabled" :
"disabled" ) );
742 WARNINGLOG( QString(
"Timeline usage was [%1] in the Preferences. But these changes won't have an effect as long as Pattern Mode is still activated." )
743 .arg( bActivate ?
"enabled" :
"disabled" ) );
751 auto pAudioEngine = pHydrogen->getAudioEngine();
752 auto pTimeline = pHydrogen->getTimeline();
754 if ( pHydrogen->getSong() ==
nullptr ) {
761 pTimeline->deleteTempoMarker( nPosition );
762 pTimeline->addTempoMarker( nPosition, fBpm );
763 pHydrogen->getAudioEngine()->handleTimelineChange();
765 pAudioEngine->unlock();
767 pHydrogen->setIsModified(
true );
776 auto pAudioEngine = pHydrogen->getAudioEngine();
778 if ( pHydrogen->getSong() ==
nullptr ) {
785 pHydrogen->getTimeline()->deleteTempoMarker( nPosition );
786 pHydrogen->getAudioEngine()->handleTimelineChange();
788 pAudioEngine->unlock();
790 pHydrogen->setIsModified(
true );
798 auto pTimeline = pHydrogen->getTimeline();
800 if ( pHydrogen->getSong() ==
nullptr ) {
805 pTimeline->deleteTag( nPosition );
806 pTimeline->addTag( nPosition, sText );
808 pHydrogen->setIsModified(
true );
817 auto pAudioEngine = pHydrogen->getAudioEngine();
819 if ( pHydrogen->getSong() ==
nullptr ) {
824 pHydrogen->getTimeline()->deleteTag( nPosition );
826 pHydrogen->setIsModified(
true );
834#ifdef H2CORE_HAVE_JACK
836 ERRORLOG(
"Unable to (de)activate Jack transport. Please select the Jack driver first." );
852 ERRORLOG(
"Unable to (de)activate Jack transport. Your Hydrogen version was not compiled with jack support." );
860#ifdef H2CORE_HAVE_JACK
861 if ( !pHydrogen->hasJackAudioDriver() ) {
862 ERRORLOG(
"Unable to (de)activate Jack timebase master. Please select the Jack driver first." );
866 pHydrogen->getAudioEngine()->lock(
RIGHT_HERE );
869 pHydrogen->onJackMaster();
872 pHydrogen->offJackMaster();
874 pHydrogen->getAudioEngine()->unlock();
877 static_cast<int>(pHydrogen->getJackTimebaseState()) );
881 ERRORLOG(
"Unable to (de)activate Jack timebase master. Your Hydrogen version was not compiled with jack support." );
889 auto pAudioEngine = pHydrogen->getAudioEngine();
890 auto pSong = pHydrogen->getSong();
892 if ( pSong ==
nullptr ) {
903 pHydrogen->sequencer_stop();
914 pAudioEngine->handleSongModeChanged();
916 pAudioEngine->unlock();
924 auto pSong = pHydrogen->getSong();
925 auto pAudioEngine = pHydrogen->getAudioEngine();
927 if ( pHydrogen->getSong() ==
nullptr ) {
933 bool bChange =
false;
940 }
else if ( ! bActivate &&
945 if ( pSong->lengthInTicks() <
946 pAudioEngine->getTransportPosition()->getTick() ) {
955 pAudioEngine->handleLoopModeChanged();
956 pAudioEngine->unlock();
960 static_cast<int>( bActivate ) );
970 if ( pDrumkit ==
nullptr ) {
971 ERRORLOG( QString(
"Drumkit [%1] could not be loaded." )
980 if ( pDrumkit !=
nullptr ) {
983 auto pSong = pHydrogen->getSong();
984 if ( pSong !=
nullptr ) {
986 INFOLOG( QString(
"Setting drumkit [%1] located at [%2]" )
987 .arg( pDrumkit->get_name() )
988 .arg( pDrumkit->get_path() ) );
990 pHydrogen->getAudioEngine()->lock(
RIGHT_HERE );
992 pSong->setDrumkit( pDrumkit, bConditional );
994 if ( pHydrogen->getSelectedInstrumentNumber() >=
995 pSong->getInstrumentList()->size() ) {
996 pHydrogen->setSelectedInstrumentNumber(
997 std::max( 0, pSong->getInstrumentList()->size() -1 ),
1001 pHydrogen->renameJackPorts( pSong );
1003 pHydrogen->getAudioEngine()->unlock();
1007 pHydrogen->setIsModified(
true );
1011 if ( pHydrogen->isUnderSessionManagement() ) {
1012 pHydrogen->setSessionDrumkitNeedsRelinking(
true );
1023 ERRORLOG(
"Provided Drumkit is not valid" );
1032 if ( sNewPath.isEmpty() ) {
1033 INFOLOG( QString(
"Upgrading kit at [%1] inplace." )
1034 .arg( sDrumkitPath ) );
1036 INFOLOG( QString(
"Upgrading kit at [%1] into [%2]." )
1037 .arg( sDrumkitPath ).arg( sNewPath ) );
1040 QFileInfo sourceFileInfo( sDrumkitPath );
1041 if ( ! sNewPath.isEmpty() ) {
1053 ERRORLOG( QString(
"Unable to upgrade drumkit [%1] in place: Folder is in read-only mode" )
1054 .arg( sDrumkitPath ) );
1059 QString sTemporaryFolder, sDrumkitDir;
1063 &sDrumkitDir, &sTemporaryFolder );
1065 if ( pDrumkit ==
nullptr ) {
1066 ERRORLOG( QString(
"Unable to load drumkit from source path [%1]" )
1067 .arg( sDrumkitPath ) );
1074 if ( ! sNewPath.isEmpty() ) {
1079 if ( ! bIsCompressed ) {
1081 QDir drumkitDir( sDrumkitDir );
1082 for (
const auto& ssFile : drumkitDir.entryList( QDir::Files ) ) {
1085 if ( ssFile.contains(
".xml" ) ) {
1089 sNewPath +
"/" + ssFile,
true,
true );
1093 sPath = sDrumkitDir;
1099 if ( ! bIsCompressed ) {
1102 QString sBackupPath =
1105 sBackupPath,
true,
true ) ) {
1106 ERRORLOG( QString(
"Unable to backup source drumkit XML file from [%1] to [%2]. We abort instead of overwriting things." )
1108 .arg( sBackupPath ) );
1114 ERRORLOG( QString(
"Unable to backup source .h2drumkit file from [%1] to [%2]. We abort instead of overwriting things." )
1115 .arg( sDrumkitPath ).arg( sBackupPath ) );
1120 sPath = sDrumkitDir;
1123 if ( ! pDrumkit->save( sPath, -1,
true,
true ) ) {
1124 ERRORLOG( QString(
"Error while saving upgraded kit to [%1]" )
1131 if ( bIsCompressed ) {
1132 QString sExportPath;
1133 if ( ! sNewPath.isEmpty() ) {
1134 sExportPath = sNewPath;
1136 sExportPath = sourceFileInfo.dir().absolutePath();
1139 if ( ! pDrumkit->exportTo( sExportPath,
"",
true,
false ) ) {
1140 ERRORLOG( QString(
"Unable to export upgrade drumkit to [%1]" )
1141 .arg( sExportPath ) );
1145 INFOLOG( QString(
"Upgraded drumkit exported as [%1]" )
1146 .arg( sExportPath +
"/" + pDrumkit->get_name() +
1151 if ( ! sTemporaryFolder.isEmpty() ) {
1155 INFOLOG( QString(
"Drumkit [%1] successfully upgraded!" )
1156 .arg( sDrumkitPath ) );
1163 INFOLOG( QString(
"Validating kit [%1]" ).arg( sDrumkitPath ) );
1165 QString sTemporaryFolder, sDrumkitDir;
1169 &sDrumkitDir, &sTemporaryFolder );
1171 if ( pDrumkit ==
nullptr ) {
1172 ERRORLOG( QString(
"Unable to load drumkit from source path [%1]" )
1173 .arg( sDrumkitPath ) );
1178 ERRORLOG( QString(
"Something went wrong in the drumkit retrieval of [%1]. Unable to load from [%2]" )
1179 .arg( sDrumkitPath ).arg( sDrumkitDir ) );
1183 auto validateXSD = [&](
const QString& sXSDPath,
const QString& sContext ) {
1187 sXSDPath,
true ) ) {
1188 ERRORLOG( QString(
"Drumkit file [%1] does not comply with [%2] XSD definition" )
1194 XMLNode root = doc.firstChildElement(
"drumkit_info" );
1195 if ( root.isNull() ) {
1196 ERRORLOG( QString(
"Drumkit file [%1] seems bricked: 'drumkit_info' node not found" )
1201 INFOLOG( QString(
"Drumkit file [%1] validates [%2] XSD definition" )
1209 if ( ! bValid && ! bCheckLegacyVersions ) {
1213 if ( ! bValid && bCheckLegacyVersions ) {
1216 for (
const auto& sPath : legacyXSDFiles ) {
1217 QString sContext( sPath );
1221 if ( validateXSD( sPath, sContext ) ) {
1232 INFOLOG( QString(
"Drumkit [%1] is valid!" )
1233 .arg( sDrumkitPath ) );
1240 std::shared_ptr<Drumkit> pDrumkit =
nullptr;
1247 *bIsCompressed =
false;
1248 *sTemporaryFolder =
"";
1251 QFileInfo sourceFileInfo( sDrumkitPath );
1257 *sDrumkitDir = sDrumkitPath;
1264 QString sDrumkitDirPath = QFileInfo( sDrumkitPath ).absoluteDir().absolutePath();
1266 *sDrumkitDir = sourceFileInfo.dir().absolutePath();
1271 *bIsCompressed =
true;
1276 sourceFileInfo.baseName() +
"_XXXXXX" );
1277 QTemporaryDir tmpDir( sTemplateName );
1278 tmpDir.setAutoRemove(
false );
1279 if ( ! tmpDir.isValid() ) {
1280 ERRORLOG( QString(
"Unable to create temporary folder using template name [%1]" )
1281 .arg( sTemplateName ) );
1285 *sTemporaryFolder = tmpDir.path();
1290 ERRORLOG( QString(
"Unabled to extract provided drumkit [%1] into [%2]" )
1291 .arg( sDrumkitPath ).arg( tmpDir.path() ) );
1302 QDir extractedDir( tmpDir.path() );
1303 QStringList extractedContent =
1304 extractedDir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot );
1305 QStringList extractedFolders =
1306 extractedDir.entryList( QDir::Dirs | QDir::NoDotAndDotDot );
1307 if ( ( extractedContent.size() != extractedFolders.size() ) ||
1308 ( extractedFolders.size() != 1 ) ) {
1309 ERRORLOG( QString(
"Unsupported content of [%1]. Expected a single folder within the archive containing all samples, metadata, as well as the drumkit.xml file. Instead:\n" )
1310 .arg( sDrumkitPath ) );
1311 for (
const auto& sFile : extractedContent ) {
1317 *sDrumkitDir = tmpDir.path() +
"/" + extractedFolders[0];
1322 ERRORLOG( QString(
"Provided source path [%1] does not point to a Hydrogen drumkit" )
1323 .arg( sDrumkitPath ) );
1333 bool bInstall =
false;
1334 if ( sTargetDir.isEmpty() ) {
1336 INFOLOG( QString(
"Installing drumkit [%1]" ).arg( sDrumkitPath ) );
1339 INFOLOG( QString(
"Extracting drumkit [%1] to [%2]" )
1340 .arg( sDrumkitPath ).arg( sTargetDir ) );
1341 sTarget = sTargetDir;
1345 ERRORLOG( QString(
"Target dir [%1] is neither a writable folder nor can it be created." )
1350 QFileInfo sKitInfo( sDrumkitPath );
1353 ERRORLOG( QString(
"Invalid drumkit path [%1]. Please provide an absolute path to a .h2drumkit file." )
1354 .arg( sDrumkitPath ) );
1359 ERRORLOG( QString(
"Unabled to extract provided drumkit [%1] into [%2]" )
1360 .arg( sDrumkitPath ).arg( sTarget ) );
1373 if ( nPatternGroup < -1 ) {
1374 ERRORLOG( QString(
"Provided column [%1] too low. Assigning 0 instead." )
1375 .arg( nPatternGroup ) );
1380 if ( pHydrogen->getSong() ==
nullptr ) {
1385 long nTotalTick = pHydrogen->getTickForColumn( nPatternGroup );
1386 if ( nTotalTick < 0 ) {
1388 ERRORLOG( QString(
"Provided column [%1] violates the allowed range [0;%2). No relocation done." )
1389 .arg( nPatternGroup )
1390 .arg( pHydrogen->getSong()->getPatternGroupVector()->size() ) );
1405 auto pAudioEngine = pHydrogen->getAudioEngine();
1407 if ( pHydrogen->getSong() ==
nullptr ) {
1414 pAudioEngine->locate( nTick, bWithJackBroadcast );
1416 pAudioEngine->unlock();
1426 return setPattern( pPattern, pPatternList->size() );
1430 auto pSong = pHydrogen->getSong();
1432 if ( pHydrogen->getSong() ==
nullptr ) {
1437 auto pPatternList = pSong->getPatternList();
1440 if ( pNewPattern ==
nullptr ) {
1441 ERRORLOG( QString(
"Unable to loading the pattern [%1]" ).arg( sPath ) );
1445 if ( nPatternPosition == -1 ) {
1446 nPatternPosition = pPatternList->size();
1449 return setPattern( pNewPattern, nPatternPosition );
1455 if ( pHydrogen->getSong() ==
nullptr ) {
1460 auto pPatternList = pHydrogen->getSong()->getPatternList();
1463 if ( !pPatternList->check_name( pPattern->
get_name() ) ){
1464 pPattern->
set_name( pPatternList->find_unused_pattern_name( pPattern->
get_name() ) );
1467 pPatternList->insert( nPatternPosition, pPattern );
1468 if ( pHydrogen->isPatternEditorLocked() ) {
1469 pHydrogen->updateSelectedPattern(
true );
1471 pHydrogen->setSelectedPatternNumber( nPatternPosition );
1473 pHydrogen->setIsModified(
true );
1484 auto pAudioEngine = pHydrogen->getAudioEngine();
1485 auto pSong = pHydrogen->getSong();
1488 if ( pSong ==
nullptr ) {
1493 INFOLOG( QString(
"Deleting pattern [%1]" ).arg( nPatternNumber ) );
1495 auto pPatternList = pSong->getPatternList();
1496 auto pPatternGroupVector = pSong->getPatternGroupVector();
1497 auto pPlayingPatterns = pAudioEngine->getPlayingPatterns();
1498 auto pNextPatterns = pAudioEngine->getNextPatterns();
1500 int nSelectedPatternNumber = pHydrogen->getSelectedPatternNumber();
1501 auto pPattern = pPatternList->get( nPatternNumber );
1503 if ( pPattern ==
nullptr ) {
1504 ERRORLOG( QString(
"Pattern [%1] not found" ).arg( nPatternNumber ) );
1512 if ( pPatternList->size() == 0 ) {
1514 pPatternList->add( pEmptyPattern );
1519 for (
const auto& ppatternList : *pPatternGroupVector ) {
1520 for (
int ii = 0; ii < ppatternList->size(); ++ii ) {
1521 if ( ppatternList->get( ii ) == pPattern ) {
1522 ppatternList->del( ii );
1532 for (
int ii = pPatternGroupVector->size() - 1; ii >= 0; --ii ) {
1533 pColumn = pPatternGroupVector->at( ii );
1534 if ( pColumn->
size() == 0 ) {
1535 pPatternGroupVector->erase( pPatternGroupVector->begin() + ii );
1543 if ( pHydrogen->isPatternEditorLocked() ) {
1544 pHydrogen->updateSelectedPattern(
false );
1545 }
else if ( nPatternNumber == nSelectedPatternNumber ) {
1546 pHydrogen->setSelectedPatternNumber( std::max( 0, nPatternNumber - 1 ),
1554 for (
int ii = 0; ii < pNextPatterns->size(); ++ii ) {
1555 if ( pNextPatterns->get( ii ) == pPattern ) {
1556 pAudioEngine->toggleNextPattern( nPatternNumber );
1563 pAudioEngine->removePlayingPattern( pPattern );
1566 pPatternList->
del( pPattern );
1568 pHydrogen->updateSongSize();
1570 pAudioEngine->unlock();
1573 for (
const auto& ppattern : *pPatternList ) {
1577 if ( it != ppattern->get_virtual_patterns()->end() ) {
1578 ppattern->virtual_patterns_del( *it );
1582 pHydrogen->updateVirtualPatterns();
1583 pHydrogen->setIsModified(
true );
1593 if ( pHydrogen->getSong() ==
nullptr ) {
1598 auto pSong = pHydrogen->getSong();
1599 auto pPatternList = pSong->getPatternList();
1600 std::vector<PatternList*>* pColumns = pSong->getPatternGroupVector();
1602 if ( nRow < 0 || nRow > pPatternList->size() ) {
1603 ERRORLOG( QString(
"Provided row [%1] is out of bound [0,%2]" )
1604 .arg( nRow ).arg( pPatternList->size() ) );
1608 auto pNewPattern = pPatternList->get( nRow );
1609 if ( pNewPattern ==
nullptr ) {
1610 ERRORLOG( QString(
"Unable to obtain Pattern in row [%1]." )
1616 pHydrogen->getAudioEngine()->lock(
RIGHT_HERE );
1617 if ( nColumn >= 0 && nColumn < pColumns->size() ) {
1619 auto pPattern = pColumn->
del( pNewPattern );
1620 if ( pPattern ==
nullptr ) {
1622 pColumn->
add( pNewPattern );
1627 for (
int ii = pColumns->size() - 1; ii >= 0; ii-- ) {
1629 if ( pColumn->
size() == 0 ) {
1630 pColumns->erase( pColumns->begin() + ii );
1637 }
else if ( nColumn >= pColumns->size() ) {
1641 for (
int ii = 0; nColumn - pColumns->size() + 1; ii++ ) {
1643 pColumns->push_back( pColumn );
1645 pColumn->
add( pNewPattern );
1648 ERRORLOG( QString(
"Provided column [%1] is out of bound [0,%2]" )
1649 .arg( nColumn ).arg( pColumns->size() ) );
1653 pHydrogen->updateSongSize();
1654 pHydrogen->updateSelectedPattern(
false );
1656 pHydrogen->getAudioEngine()->unlock();
1658 pHydrogen->setIsModified(
true );
1671 auto pAudioEngine = pHydrogen->getAudioEngine();
1673 pAudioEngine->getMetronomeInstrument()->set_volume(
1674 pPref->m_fMetronomeVolume );
1689 bool bAlreadyContained =
false;
1691 std::vector<QString> recentFiles = pPref->getRecentFiles();
1693 recentFiles.insert( recentFiles.begin(), sFilename );
1695 if ( std::find( recentFiles.begin(), recentFiles.end(),
1696 sFilename ) != recentFiles.end() ) {
1700 std::vector<QString> sTmpVec;
1701 for (
const auto& ssFilename : recentFiles ) {
1702 if ( std::find( sTmpVec.begin(), sTmpVec.end(), ssFilename ) ==
1705 sTmpVec.push_back( ssFilename );
1709 recentFiles = sTmpVec;
1712 pPref->setRecentFiles( recentFiles );
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
@ Playing
Transport is rolling.
void unlock()
Mutex unlocking of the AudioEngine.
void lock(const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
bool locateToColumn(int nPatternGroup)
Relocates transport to the beginning of a particular column/Pattern group.
bool setPattern(Pattern *pPattern, int nPatternNumber)
Opens a pattern to the current pattern list.
bool addTag(int nPosition, const QString &sText)
Adds a tag to the Timeline.
bool setSong(std::shared_ptr< Song > pSong, bool bRelinking=true)
Sets a H2Core::Song to be used by Hydrogen.
bool sendStripIsSoloedFeedback(int nStrip)
bool sendMetronomeIsActiveFeedback()
bool setMetronomeIsActive(bool isActive)
void updatePreferences()
In case a different preferences file was loaded with Hydrogen already fully set up this function refr...
bool openSong(const QString &songPath, const QString &sRecoverSongPath="")
Opens the H2Core::Song specified in songPath.
bool locateToTick(long nTick, bool bWithJackBroadcast=true)
Relocates transport to a particular tick.
bool sendStripPanFeedback(int nStrip)
bool deleteTempoMarker(int nPosition)
Delete a tempo marker from the Timeline.
std::shared_ptr< Instrument > getStrip(int nStrip) const
bool newPattern(const QString &sPatternName)
Creates an empty pattern and adds it to the pattern list.
bool toggleStripIsMuted(int nStrip)
bool newSong(const QString &songPath)
Create an empty H2Core::Song, which will be stored in songPath.
bool savePreferences()
Saves the current state of the H2Core::Preferences.
std::shared_ptr< Drumkit > retrieveDrumkit(const QString &sDrumkitPath, bool *bIsCompressed, QString *sDrumkitDir, QString *sTemporaryFolder)
Loads the drumkit specified in sDrumkitPath.
bool sendMasterIsMutedFeedback()
bool setStripVolume(int nStrip, float fVolumeValue, bool bSelectStrip)
bool toggleStripIsSoloed(int nStrip)
bool sendStripVolumeFeedback(int nStrip)
bool activateSongMode(bool bActivate)
Switches between Song and Pattern mode of playback.
bool validateDrumkit(const QString &sDrumkitPath, bool bCheckLegacyVersions=false)
Checks whether the provided drumkit in sDrumkitPath can be found, can be loaded, and does comply with...
bool setDrumkit(const QString &sDrumkit, bool bConditional=true)
Wrapper around setDrumkit() that allows loading drumkits by name or path.
bool setStripPanSym(int nStrip, float fValue, bool bSelectStrip)
bool toggleGridCell(int nColumn, int nRow)
Fills or clears a specific grid cell in the SongEditor.
bool removePattern(int nPatternNumber)
Removes a pattern from the pattern list.
bool activateLoopMode(bool bActivate)
Toggle loop mode of playback.
bool upgradeDrumkit(const QString &sDrumkitPath, const QString &sNewPath="")
Upgrades the drumkit found at absolute path sDrumkitPath.
void insertRecentFile(const QString sFilename)
Add sFilename to the list of recent songs in Preferences::m_recentFiles.
bool setMasterIsMuted(bool isMuted)
bool activateJackTransport(bool bActivate)
(De)activates the usage of Jack transport.
bool setStripIsMuted(int nStrip, bool isMuted)
bool setMasterVolume(float masterVolumeValue)
bool activateTimeline(bool bActivate)
(De)activates the usage of the Timeline.
bool activateJackTimebaseMaster(bool bActivate)
(De)activates the usage of Jack timebase master.
bool sendStripIsMutedFeedback(int nStrip)
bool setStripIsSoloed(int nStrip, bool isSoloed)
bool sendMasterVolumeFeedback()
bool initExternalControlInterfaces()
bool saveSongAs(const QString &sNewFilename)
Saves the current H2Core::Song to the path provided in sNewFilename.
bool extractDrumkit(const QString &sDrumkitPath, const QString &sTargetDir="")
Extracts the compressed .h2drumkit file in sDrumkitPath into sTargetDir.
bool saveSong()
Saves the current H2Core::Song.
bool deleteTag(int nPosition)
Delete a tag from the Timeline.
bool setStripPan(int nStrip, float fValue, bool bSelectStrip)
bool quit()
Triggers the shutdown of Hydrogen.
bool addTempoMarker(int nPosition, float fBpm)
Adds a tempo marker to the Timeline.
const int m_nDefaultMidiFeedbackChannel
bool openPattern(const QString &sPath, int nPatternNumber=-1)
Opens a pattern from disk and adds it to the pattern list.
bool handleOutgoingControlChanges(std::vector< int > params, int nValue)
static std::shared_ptr< Drumkit > load(const QString &dk_dir, bool bUpgrade=true, bool bSilent=false)
Load drumkit information from a directory.
static bool install(const QString &sSourcePath, const QString &sTargetPath="", bool bSilent=false)
Extract a .h2drumkit file.
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 bool file_copy(const QString &src, const QString &dst, bool overwrite=false, bool bSilent=false)
copy a source file to a destination
static bool dir_readable(const QString &path, bool silent=false)
returns true if the given path is a readable regular directory
static bool isSongPathValid(const QString &sSongPath, bool bCheckExistance=false)
Checks the path pointing to a .h2song.
static bool drumkit_valid(const QString &dk_path)
returns true if the path contains a usable drumkit
static QString usr_drumkits_dir()
returns user drumkits path
static QStringList drumkit_xsd_legacy_paths()
static QString drumkit_backup_path(const QString &dk_path)
Create a backup path from a drumkit path.
static QString drumkit_xsd_path()
returns the path to the drumkit XSD (xml schema definition) file
static bool dir_writable(const QString &path, bool silent=false)
returns true if the given path is a writable regular directory
static QString empty_song_path()
Provides the full path to the current empty song.
static QString drumkit_file(const QString &dk_path)
returns the path to the xml file within a supposed drumkit path
static QString tmp_dir()
returns temp path
static const QString drumkit_ext
static bool path_usable(const QString &path, bool create=true, bool silent=false)
returns true if the path is a readable and writable regular directory, create if it not exists
static QString drumkit_xml()
Returns filename and extension of the expected drumkit file.
static QString drumkit_xsd()
returns the drumkit XSD (xml schema definition) name
static QString xsd_dir()
returns system xsd path
static bool file_readable(const QString &path, bool silent=false)
returns true if the given path is an existing readable regular file
std::shared_ptr< Song > getSong() const
Get the current song.
@ unavailable
No GUI available.
@ ready
There is a working GUI.
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
MidiOutput * getMidiOutput() const
AudioEngine * getAudioEngine() const
SoundLibraryDatabase * getSoundLibraryDatabase() const
@ Slave
An external program is timebase master and Hydrogen will disregard all tempo markers on the Timeline ...
virtual void handleOutgoingControlChange(int param, int value, int channel)=0
PatternList is a collection of patterns.
void add(Pattern *pattern, bool bAddVirtuals=false)
add a pattern to the list
Pattern * del(int idx)
remove the pattern at a given index, does not delete it
int size() const
returns the numbers of patterns
Pattern class is a Note container.
void set_name(const QString &name)
get the name of the pattern
const QString & get_name() const
set the category of the pattern
const virtual_patterns_t * get_virtual_patterns() const
get the flattened virtual pattern set
static Pattern * load_file(const QString &pattern_path, std::shared_ptr< InstrumentList > instruments)
load a pattern from a file
virtual_patterns_t::const_iterator virtual_patterns_cst_it_t
Manager for User Preferences File (singleton)
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
int m_bJackMasterMode
Specifies if Hydrogen should run as JACK time master.
bool savePreferences()
Save the preferences file.
bool m_bEnableMidiFeedback
void setLastSongFilename(const QString &filename)
bool m_bUseMetronome
If set to true, samples of the metronome will be added to H2Core::AudioEngine::m_songNoteQueue and th...
@ NO_JACK_TRANSPORT
Specifies whether or not to use JACK transport capabilities.
@ USE_JACK_TIME_MASTER
Specifies that Hydrogen is using in the time master mode and will thus control specific aspects of th...
@ NO_JACK_TIME_MASTER
Specifies that Hydrogen is note using in the time master mode.
@ USE_JACK_TRANSPORT
Specifies whether or not to use JACK transport capabilities.
int m_bJackTransportMode
Specifies whether or not Hydrogen will use the JACK transport system.
static std::shared_ptr< Song > load(const QString &sFilename, bool bSilent=false)
Load a song from file.
@ Finishing
Transport is still in loop mode (frames and ticks larger than song size are allowed) but playback end...
static std::shared_ptr< Song > getEmptySong()
void updateDrumkits(bool bTriggerEvent=true)
std::shared_ptr< Drumkit > getDrumkit(const QString &sDrumkitPath, bool bLoad=true)
Retrieve a drumkit from the database.
XMLDoc is a subclass of QDomDocument with read and write methods.
bool read(const QString &filepath, const QString &schemapath=nullptr, bool bSilent=false)
read the content of an xml file
XMLNode is a subclass of QDomNode with read and write values methods.
The MidiMap maps MidiActions to MidiEvents.
std::vector< int > findCCValuesByActionParam1(QString sActionType, QString sParam1)
static MidiMap * get_instance()
Returns a pointer to the current MidiMap singleton stored in __instance.
std::vector< int > findCCValuesByActionType(QString sActionType)
static void linkDrumkit(std::shared_ptr< H2Core::Song > pSong)
Responsible for linking a drumkit on user or system level into the session folder and updating all co...
static OscServer * get_instance()
Returns a pointer to the current OscServer singleton stored in __instance.
void handleAction(std::shared_ptr< Action > pAction)
Function called by H2Core::CoreActionController::initExternalControlInterfaces() to inform all client...
@ EVENT_RELOCATION
Triggered in case there is a relocation of the transport position while trasnsport is not rolling.
@ EVENT_INSTRUMENT_PARAMETERS_CHANGED
Some parameters of an instrument have been changed.
@ EVENT_DRUMKIT_LOADED
A the current drumkit was replaced by a new one.
@ EVENT_JACK_TRANSPORT_ACTIVATION
Toggles the button indicating the usage Jack transport.
@ EVENT_PATTERN_MODIFIED
A pattern was added, deleted, or modified.
@ EVENT_TIMELINE_UPDATE
Tells the GUI some parts of the Timeline (tempo markers or tags) were modified.
@ EVENT_UPDATE_SONG
Event triggering HydrogenApp::updateSongEvent() whenever the Song was changed outside of the GUI,...
@ EVENT_LOOP_MODE_ACTIVATION
Toggles the button indicating the usage loop mode.
@ EVENT_GRID_CELL_TOGGLED
@ EVENT_QUIT
Triggering HydrogenApp::quitEvent() and enables a shutdown of the entire application via the command ...
@ EVENT_UPDATE_PREFERENCES
Event triggering the loading or saving of the H2Core::Preferences whenever they were changed outside ...
@ EVENT_JACK_TIMEBASE_STATE_CHANGED
Toggles the button indicating the usage Jack timebase master and informs the GUI about a state change...