hydrogen 1.2.6
HydrogenApp.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#include <core/config.h>
24#include <core/Version.h>
25#include <core/Hydrogen.h>
26#include <core/EventQueue.h>
27#include <core/FX/LadspaFX.h>
30
31#include "HydrogenApp.h"
32#include "CommonStrings.h"
34#include "MainForm.h"
35#include "PlayerControl.h"
36#include "AudioEngineInfoForm.h"
37#include "FilesystemInfoForm.h"
38#include "LadspaFXProperties.h"
39#include "InstrumentRack.h"
40#include "Director.h"
41
52#include "Mixer/Mixer.h"
53#include "Mixer/MixerLine.h"
54#include "UndoActions.h"
55
58
60#include "Widgets/InfoBar.h"
61
62#include <QtGui>
63#include <QtWidgets>
64
65
66using namespace H2Core;
67
68
70
72 : m_pMainForm( pMainForm )
73 , m_pMixer( nullptr )
74 , m_pPatternEditorPanel( nullptr )
75 , m_pAudioEngineInfoForm( nullptr )
76 , m_pSongEditorPanel( nullptr )
77 , m_pPlayerControl( nullptr )
78 , m_pPlaylistDialog( nullptr )
79 , m_pSampleEditor( nullptr )
80 , m_pDirector( nullptr )
82 , m_bufferedChanges( H2Core::Preferences::Changes::None )
83 , m_pMainScrollArea( new QScrollArea )
84{
85 m_pInstance = this;
86
87 m_pEventQueueTimer = new QTimer(this);
88 connect( m_pEventQueueTimer, SIGNAL( timeout() ), this, SLOT( onEventQueueTimer() ) );
90
91 // Wait for m_nPreferenceUpdateTimeout milliseconds of no update
92 // signal before propagating the update. Else importing/resetting a
93 // theme will slow down the GUI significantly.
94 m_pPreferencesUpdateTimer = new QTimer( this );
95 m_pPreferencesUpdateTimer->setSingleShot( true );
96 connect( m_pPreferencesUpdateTimer, SIGNAL(timeout()), this, SLOT(propagatePreferences()) );
97
98 m_pCommonStrings = std::make_shared<CommonStrings>();
99
100 //setup the undo stack
101 m_pUndoStack = new QUndoStack( this );
102
104
106
108
109 // restore audio engine form properties
111 WindowProperties audioEngineInfoProp = pPref->getAudioEngineInfoProperties();
112 setWindowProperties( m_pAudioEngineInfoForm, audioEngineInfoProp, SetX + SetY );
113
115
116 m_pPlaylistDialog = new PlaylistDialog( nullptr );
117 WindowProperties playlistDialogProp = pPref->getPlaylistDialogProperties();
118 setWindowProperties( m_pPlaylistDialog, playlistDialogProp, SetAll );
119
120 m_pDirector = new Director( nullptr );
121 WindowProperties directorProp = pPref->getDirectorProperties();
122 setWindowProperties( m_pDirector, directorProp, SetAll );
123
124 // Initially keyboard cursor is hidden.
126
127 // Since HydrogenApp does implement some handler functions for
128 // Events as well, it should be registered as an Eventlistener
129 // itself.
130 addEventListener( this );
131
132 connect( this, &HydrogenApp::preferencesChanged,
134 connect( this, &HydrogenApp::preferencesChanged,
136}
137
138void HydrogenApp::setWindowProperties( QWidget *pWindow, WindowProperties &prop, unsigned flags ) {
139 if ( flags & SetVisible ) {
140 if ( prop.visible) {
141 pWindow->show();
142 } else {
143 pWindow->hide();
144 }
145 }
146
147 // Preserve the current values of anything we're not setting.
148 QRect oldGeometry = pWindow->geometry();
149 if ( prop.m_geometry.size() == 0 ) {
150 // No geometry saved in preferences. Most likely an old preferences file. Set the size and shape
151 pWindow->resize( prop.width, prop.height );
152 pWindow->move( prop.x, prop.y );
153 prop.m_geometry = pWindow->saveGeometry();
154 }
155
156 // restore geometry will also ensure things are visible if screen geometry has changed.
157 pWindow->restoreGeometry( prop.m_geometry );
158
159 // For anything that we're not setting, restore the previous values.
160 QRect newGeometry = pWindow->geometry();
161 if ( !( flags & SetX ) ) {
162 newGeometry.setX( oldGeometry.x() );
163 }
164 if ( !( flags & SetY ) ) {
165 newGeometry.setY( oldGeometry.y() );
166 }
167 if ( !( flags & SetWidth ) ) {
168 newGeometry.setWidth( oldGeometry.width() );
169 }
170 if ( !( flags & SetHeight ) ) {
171 newGeometry.setHeight( oldGeometry.height() );
172 }
173
174 // If a window is fixed-size, don't restore it full-screen (macOS sometimes does this, annoyingly)
175 if ( pWindow->minimumSize() == pWindow->maximumSize() ) {
176 if ( pWindow->isFullScreen()) {
177 pWindow->showNormal();
178 }
179 }
180
181 if ( oldGeometry != newGeometry ) {
182 pWindow->setGeometry( newGeometry );
183 }
184}
185
186
188 WindowProperties prop;
189 prop.x = pWindow->x();
190 prop.y = pWindow->y();
191 prop.height = pWindow->height();
192 prop.width = pWindow->width();
193 prop.visible = pWindow->isVisible();
194 prop.m_geometry = pWindow->saveGeometry();
195
196 return prop;
197}
198
199
201{
202 INFOLOG( "[~HydrogenApp]" );
203 m_pEventQueueTimer->stop();
204
205
206 //delete the undo tmp directory
208
211 delete m_pMixer;
212 delete m_pPlaylistDialog;
213 delete m_pDirector;
214 delete m_pSampleEditor;
215
216 if ( m_pTab ) {
217 delete m_pTab;
218 }
219 if ( m_pSplitter ) {
220 delete m_pSplitter;
221 }
222
223 #ifdef H2CORE_HAVE_LADSPA
224 for (uint nFX = 0; nFX < MAX_FX; nFX++) {
225 delete m_pLadspaFXProperties[nFX];
226 }
227 #endif
228
229 Hydrogen *pHydrogen = Hydrogen::get_instance();
230 if (pHydrogen) {
231 // Hydrogen calls removeSong on from its destructor, so here we just delete the objects:
232 delete pHydrogen;
233 }
234
235 m_pInstance = nullptr;
236
237}
238
239
240
242{
245
246 // MAINFORM
247 WindowProperties mainFormProp = pPref->getMainFormProperties();
249
250 m_pSplitter = new QSplitter( m_pMainScrollArea );
251 m_pSplitter->setOrientation( Qt::Vertical );
252 m_pSplitter->setOpaqueResize( true );
253
254 m_pTab = new QTabWidget( m_pMainScrollArea );
255 m_pTab->setObjectName( "TabbedInterface" );
256
257 // SONG EDITOR
258 if( layout == InterfaceTheme::Layout::SinglePane ) {
260 } else {
262 }
263 // trigger a relocation to sync the transport position of the
264 // editors in the panel.
266
267 WindowProperties songEditorProp = pPref->getSongEditorProperties();
269
270 if( layout == InterfaceTheme::Layout::Tabbed ) {
271 m_pTab->addTab( m_pSongEditorPanel, tr("Song Editor") );
272 }
273
274 // this HBox will contain the InstrumentRack and the Pattern editor
275 QWidget *pSouthPanel = new QWidget( m_pSplitter );
276 pSouthPanel->setObjectName( "SouthPanel" );
277 QHBoxLayout *pEditorHBox = new QHBoxLayout();
278 pEditorHBox->setSpacing( 5 );
279 pEditorHBox->setContentsMargins( 0, 0, 0, 0 );
280 pSouthPanel->setLayout( pEditorHBox );
281
282 // INSTRUMENT RACK
283 m_pInstrumentRack = new InstrumentRack( nullptr );
284 WindowProperties instrumentRackProp = pPref->getInstrumentRackProperties();
285 m_pInstrumentRack->setHidden( !instrumentRackProp.visible );
286
287 if( layout == InterfaceTheme::Layout::Tabbed ){
288 m_pTab->setMovable( false );
289 m_pTab->setTabsClosable( false );
290 m_pTab->addTab( pSouthPanel, tr( "Instrument + Pattern") );
291 }
292
293 // PATTERN EDITOR
295 // Sync the playhead position in all editors all objects are available.
296 m_pPatternEditorPanel->getPatternEditorRuler()->updatePosition( true );
297 WindowProperties patternEditorProp = pPref->getPatternEditorProperties();
299
300 pEditorHBox->addWidget( m_pPatternEditorPanel );
301 pEditorHBox->addWidget( m_pInstrumentRack );
302
303 // PLayer control
304 m_pPlayerControl = new PlayerControl( nullptr );
305
306 QWidget *mainArea = new QWidget( m_pMainForm ); // this is the main widget
307 m_pMainForm->setCentralWidget( mainArea );
308
309 // LAYOUT!!
310 m_pMainVBox = new QVBoxLayout();
311 m_pMainVBox->setSpacing( 1 );
312 m_pMainVBox->setContentsMargins( 0, 0, 0, 0 );
313 m_pMainVBox->addWidget( m_pPlayerControl );
314
315 m_pMainVBox->addSpacing( 3 );
316
317 if( layout == InterfaceTheme::Layout::SinglePane ) {
318 m_pMainVBox->addWidget( m_pSplitter );
319 } else {
320 m_pMainVBox->addWidget( m_pTab );
321 }
322
323 mainArea->setLayout( m_pMainVBox );
324
325 mainArea->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
326 mainArea->setMinimumSize( 1000,
327 180 + // menu bar, margins etc.
334
335 m_pMainScrollArea->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
336 m_pMainScrollArea->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
337 m_pMainScrollArea->setWidget( mainArea );
338 m_pMainScrollArea->setWidgetResizable( true );
339
340 m_pMainForm->setCentralWidget( m_pMainScrollArea );
341
342 // MIXER
343 m_pMixer = new Mixer(nullptr);
344 m_pMixer->setObjectName( "Mixer" );
345 WindowProperties mixerProp = pPref->getMixerProperties();
346
347 if ( layout != InterfaceTheme::Layout::SinglePane ) {
348 mixerProp.visible = false;
349 }
350 setWindowProperties( m_pMixer, mixerProp );
351
352 if( layout == InterfaceTheme::Layout::Tabbed ){
353 m_pTab->addTab(m_pMixer,tr("Mixer"));
354 }
355
356 m_pMixer->updateMixer();
357
358#ifdef H2CORE_HAVE_LADSPA
359 // LADSPA FX
360 for (uint nFX = 0; nFX < MAX_FX; nFX++) {
361 m_pLadspaFXProperties[nFX] = new LadspaFXProperties( nullptr, nFX );
362 m_pLadspaFXProperties[nFX]->hide();
363 WindowProperties prop = pPref->getLadspaProperties(nFX);
364 setWindowProperties( m_pLadspaFXProperties[ nFX ], prop, SetWidth + SetHeight );
365 }
366#endif
367
368 if( layout == InterfaceTheme::Layout::Tabbed ){
369 m_pTab->setCurrentIndex( Preferences::get_instance()->getLastOpenTab() );
370 QObject::connect(m_pTab, SIGNAL(currentChanged(int)),this,SLOT(currentTabChanged(int)));
371 }
372}
373
374
376 InfoBar *pInfoBar = new InfoBar();
377 m_pMainVBox->insertWidget( 1, pInfoBar );
378 return pInfoBar;
379}
380
381
382
387
389{
390#ifdef H2CORE_HAVE_LADSPA
391 for (uint nFX = 0; nFX < MAX_FX; nFX++) {
392 m_pLadspaFXProperties[nFX]->close();
393 }
394#endif
395}
396
397bool HydrogenApp::openSong( QString sFilename ) {
398 auto pHydrogen = Hydrogen::get_instance();
399 auto pCoreActionController = pHydrogen->getCoreActionController();
400
401 // Check whether there is an autosave file next to it
402 // containing newer content.
403 QFileInfo fileInfo( sFilename );
404
405 // Ensure the path to the file is not relative.
406 if ( fileInfo.isRelative() ) {
407 sFilename = fileInfo.absoluteFilePath();
408 }
409
410 // In case the user did open a hidden file, the baseName()
411 // will be an empty string.
412 QString sBaseName( fileInfo.completeBaseName() );
413 if ( sBaseName.startsWith( "." ) ) {
414 sBaseName.remove( 0, 1 );
415 }
416
417 // Hidden autosave file (recent version)
418 QFileInfo autoSaveFileRecent( QString( "%1/.%2.autosave.h2song" )
419 .arg( fileInfo.absoluteDir().absolutePath() )
420 .arg( sBaseName ) );
421 // Visible autosave file (older version)
422 QFileInfo autoSaveFileOld( QString( "%1/%2.autosave.h2song" )
423 .arg( fileInfo.absoluteDir().absolutePath() )
424 .arg( sBaseName ) );
425 QString sRecoverFilename = "";
426 if ( autoSaveFileRecent.exists() &&
427 autoSaveFileRecent.lastModified() >
428 fileInfo.lastModified() ) {
429 sRecoverFilename = autoSaveFileRecent.absoluteFilePath();
430 } else if ( autoSaveFileOld.exists() &&
431 autoSaveFileOld.lastModified() >
432 fileInfo.lastModified() ) {
433 sRecoverFilename = autoSaveFileOld.absoluteFilePath();
434 }
435
436 if ( ! sRecoverFilename.isEmpty() ) {
437 QMessageBox msgBox;
438 // Not commonized in CommmonStrings as it is required before
439 // HydrogenApp was instantiated.
440 msgBox.setText( tr( "There are unsaved changes." ) );
441 msgBox.setInformativeText( tr( "Do you want to recover them?" ) );
442 msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Discard );
443 msgBox.setDefaultButton( QMessageBox::Discard );
444 msgBox.setWindowTitle( "Hydrogen" );
445 msgBox.setIcon( QMessageBox::Question );
446 int nRet = msgBox.exec();
447
448 if ( nRet == QMessageBox::Discard ) {
449 sRecoverFilename = "";
450 }
451 }
452
453 if ( ! pCoreActionController->openSong( sFilename, sRecoverFilename ) ) {
454 QMessageBox msgBox;
455 // Not commonized in CommmonStrings as it is required before
456 // HydrogenApp was instantiated.
457 msgBox.setText( tr( "Error loading song." ) );
458 msgBox.setWindowTitle( "Hydrogen" );
459 msgBox.setIcon( QMessageBox::Warning );
460 msgBox.exec();
461 return false;
462 }
463
464 return true;
465}
466
467bool HydrogenApp::openSong( std::shared_ptr<Song> pSong ) {
468
469 auto pCoreActionController = Hydrogen::get_instance()->getCoreActionController();
470 if ( ! pCoreActionController->openSong( pSong ) ) {
471 QMessageBox msgBox;
472 // Not commonized in CommmonStrings as it is required before
473 // HydrogenApp was instantiated.
474 msgBox.setText( tr( "Error loading song." ) );
475 msgBox.setWindowTitle( "Hydrogen" );
476 msgBox.setIcon( QMessageBox::Warning );
477 msgBox.exec();
478 return false;
479 }
480
481 return true;
482}
483
485 auto pHydrogen = Hydrogen::get_instance();
486 auto pCoreActionController = pHydrogen->getCoreActionController();
487
488 // Check whether there is an autosave file next to it
489 // containing newer content.
490 QString sFilename( H2Core::Filesystem::empty_song_path() );
491 QFileInfo fileInfo( sFilename );
492
493 // In case the user did open a hidden file, the baseName()
494 // will be an empty string.
495 QString sBaseName( fileInfo.completeBaseName() );
496 if ( sBaseName.startsWith( "." ) ) {
497 sBaseName.remove( 0, 1 );
498 }
499
500 QFileInfo autoSaveFile( QString( "%1/.%2.autosave.h2song" )
501 .arg( fileInfo.absoluteDir().absolutePath() )
502 .arg( sBaseName ) );
503 QString sRecoverFilename = "";
504
505 // Since there is no original file we can not check whether these
506 // changes have been done "recently". It's up to the calling
507 // function to ensure the corresponding empty song was indeed the
508 // last one opened by the user.
509 if ( autoSaveFile.exists() ) {
510 sRecoverFilename = autoSaveFile.absoluteFilePath();
511 }
512
513 if ( ! sRecoverFilename.isEmpty() ) {
514 QMessageBox msgBox;
515 // Not commonized in CommmonStrings as it is required before
516 // HydrogenApp was instantiated.
517 msgBox.setText( tr( "There are unsaved changes." ) );
518 msgBox.setInformativeText( tr( "Do you want to recover them?" ) );
519 msgBox.setStandardButtons( QMessageBox::Ok | QMessageBox::Discard );
520 msgBox.setDefaultButton( QMessageBox::Discard );
521 msgBox.setWindowTitle( "Hydrogen" );
522 msgBox.setIcon( QMessageBox::Question );
523 int nRet = msgBox.exec();
524
525 if ( nRet == QMessageBox::Discard ) {
526 sRecoverFilename = "";
527 }
528 }
529
530 if ( sRecoverFilename.isEmpty() ) {
531 return false;
532 }
533
534 if ( ! pCoreActionController->openSong( sFilename, sRecoverFilename ) ) {
535 QMessageBox msgBox;
536 // Not commonized in CommmonStrings as it is required before
537 // HydrogenApp was instantiated.
538 msgBox.setText( tr( "Error loading song." ) );
539 msgBox.setWindowTitle( "Hydrogen" );
540 msgBox.setIcon( QMessageBox::Warning );
541 msgBox.exec();
542 return false;
543 }
544
545 // The song has not been properly saved yet. Also this prevents
546 // the autosave file we just loaded from being removed in case the
547 // user decides to quit and reopen Hydrogen right after this call
548 // without introducing any changes.
549 pHydrogen->setIsModified( true );
550
551 return true;
552}
553
555{
556 /*
557 * Switch to Mixer tab with alt+m in tabbed mode,
558 * otherwise open mixer window
559 */
560
562
563 if ( layout == InterfaceTheme::Layout::Tabbed ) {
564 m_pTab->setCurrentIndex( 2 );
565 } else {
566 m_pMixer->setVisible( show );
567 }
568
569 m_pMainForm->update_mixer_checkbox();
570}
571
573{
574 /*
575 * Switch to pattern editor/instrument tab in tabbed mode,
576 * otherwise hide instrument panel
577 */
578
580
581 if ( layout == InterfaceTheme::Layout::Tabbed ) {
582 m_pTab->setCurrentIndex( 1 );
583 getInstrumentRack()->setHidden( show );
584 } else {
585 getInstrumentRack()->setHidden( show );
586 }
587 m_pMainForm->update_instrument_checkbox( !show );
588}
589
590
591
593{
594 PreferencesDialog preferencesDialog(m_pMainForm);
595 preferencesDialog.exec();
596}
597
598
599
600
601void HydrogenApp::showStatusBarMessage( const QString& sMessage, const QString& sCaller )
602{
603 if ( m_pPlayerControl != nullptr ) {
604 m_pPlayerControl->showStatusBarMessage( sMessage, sCaller );
605 }
606}
607
609 const auto pAudioDriver = Hydrogen::get_instance()->getAudioOutput();
610 if ( pAudioDriver == nullptr ) {
611 ERRORLOG( "AudioDriver is not ready!" );
612 return;
613 }
614 showStatusBarMessage( QString( "XRUNS [%1]!!!" ) .arg( pAudioDriver->getXRuns() ) );
615}
616
618{
619 auto pSong = Hydrogen::get_instance()->getSong();
620 if ( pSong == nullptr ) {
621 ERRORLOG( "invalid song" );
622 assert(pSong);
623 return;
624 }
625
626 QString sTitle = Filesystem::untitled_song_name();
627
628 QString sSongName( pSong->getName() );
629 QString sFilePath( pSong->getFilename() );
630
631 if ( sFilePath == Filesystem::empty_song_path() ||
632 sFilePath.isEmpty() ) {
633 // An empty song is _not_ associated with a file. Therefore,
634 // we mustn't show the file name.
635 if ( ! sSongName.isEmpty() ) {
636 sTitle = sSongName;
637 }
638 } else {
639 QFileInfo fileInfo( sFilePath );
640
641 if ( sSongName == Filesystem::untitled_song_name() ||
642 sSongName == fileInfo.completeBaseName() ) {
643 // The user did not alter the default name of the song or
644 // set the song name but also named the corresponding file
645 // accordingly. We'll just show the file name to avoid
646 // duplication.
647 sTitle = fileInfo.fileName();
648
649 } else {
650 // The user did set the song name but used a different
651 // name for the corresponding file. We'll show both to
652 // make this mismatch transparent.
653 sTitle = QString( "%1 [%2]" ).arg( sSongName )
654 .arg( fileInfo.fileName() );
655 }
656 }
657
658 if( pSong->getIsModified() ){
659 sTitle.append( " (" + tr( "modified" ) + ")" );
660 }
661
662 m_pMainForm->setWindowTitle( ( "Hydrogen " + QString( get_version().c_str()) +
663 QString( " - " ) + sTitle ) );
664}
665
666
672
678
680{
681 if ( m_pPlaylistDialog->isVisible() ) {
682 m_pPlaylistDialog->hide();
683 } else {
684 m_pPlaylistDialog->show();
685 }
686 m_pMainForm->update_playlist_checkbox();
687}
688
689
691{
692 if ( m_pDirector->isVisible() ) {
693 m_pDirector->hide();
694 } else {
695 m_pDirector->show();
696 }
697 m_pMainForm->update_director_checkbox();
698}
699
700
701void HydrogenApp::showSampleEditor( QString name, int mSelectedComponemt, int mSelectedLayer )
702{
703
704 if ( m_pSampleEditor ){
705 QApplication::setOverrideCursor(Qt::WaitCursor);
706 m_pSampleEditor->close();
707 delete m_pSampleEditor;
708 m_pSampleEditor = nullptr;
709 QApplication::restoreOverrideCursor();
710 }
711 QApplication::setOverrideCursor(Qt::WaitCursor);
712 m_pSampleEditor = new SampleEditor( nullptr, mSelectedComponemt, mSelectedLayer, name );
713 m_pSampleEditor->show();
714 QApplication::restoreOverrideCursor();
715}
716
718 showStatusBarMessage( QString( tr( "Drumkit [%1] loaded from [%2]" )
719 .arg( Hydrogen::get_instance()->getLastLoadedDrumkitName() )
720 .arg( Hydrogen::get_instance()->getLastLoadedDrumkitPath() ) ) );
721}
722
727
729{
730 // use the timer to do schedule instrument slaughter;
732
733 Event event;
734 while ( ( event = pQueue->pop_event() ).type != EVENT_NONE ) {
735
736 if ( m_eventListenersToAdd.size() > 0 ||
737 m_eventListenersToRemove.size() > 0 ) {
739 }
740
741 // Provide the event to all EventListeners registered to
742 // HydrogenApp. By registering itself as EventListener and
743 // implementing at least on the methods used below a
744 // particular GUI component can react on specific events.
745 for ( const auto& pListener : m_eventListeners ) {
746 if ( m_eventListenersToRemove.size() > 0 &&
747 m_eventListenersToRemove.find( pListener ) !=
749 // This listener was scheduled to be removed. Most probably the
750 // corresponding object is already destructed and we would risk
751 // a segfault when attempting to call its methods.
752 continue;
753 }
754
755 switch ( event.type ) {
756 case EVENT_STATE:
757 pListener->stateChangedEvent( static_cast<H2Core::AudioEngine::State>(event.value) );
758 break;
759
761 pListener->playingPatternsChangedEvent();
762 break;
763
765 pListener->nextPatternsChangedEvent();
766 break;
767
769 pListener->patternModifiedEvent();
770 break;
771
773 pListener->songModifiedEvent();
774 break;
775
777 pListener->selectedPatternChangedEvent();
778 break;
779
781 pListener->selectedInstrumentChangedEvent();
782 break;
783
785 pListener->instrumentParametersChangedEvent( event.value );
786 break;
787
789 pListener->midiActivityEvent();
790 break;
791
792 case EVENT_NOTEON:
793 pListener->noteOnEvent( event.value );
794 break;
795
796 case EVENT_ERROR:
797 pListener->errorEvent( event.value );
798 break;
799
800 case EVENT_XRUN:
801 pListener->XRunEvent();
802 break;
803
804 case EVENT_METRONOME:
805 pListener->metronomeEvent( event.value );
806 break;
807
808 case EVENT_PROGRESS:
809 pListener->progressEvent( event.value );
810 break;
811
813 pListener->jacksessionEvent( event.value );
814 break;
815
817 pListener->playlistLoadSongEvent( event.value );
818 break;
819
820 case EVENT_UNDO_REDO:
821 pListener->undoRedoActionEvent( event.value );
822 break;
823
825 pListener->tempoChangedEvent( event.value );
826 break;
827
829 pListener->updatePreferencesEvent( event.value );
830 break;
831
833 pListener->updateSongEvent( event.value );
834 break;
835
836 case EVENT_QUIT:
837 pListener->quitEvent( event.value );
838 break;
839
841 pListener->timelineActivationEvent();
842 break;
843
845 pListener->timelineUpdateEvent( event.value );
846 break;
847
849 pListener->jackTransportActivationEvent();
850 break;
851
853 pListener->jackTimebaseStateChangedEvent( event.value );
854 break;
855
857 pListener->songModeActivationEvent();
858 break;
859
861 pListener->stackedModeActivationEvent( event.value );
862 break;
863
865 pListener->loopModeActivationEvent();
866 break;
867
869 pListener->actionModeChangeEvent( event.value );
870 break;
871
873 pListener->gridCellToggledEvent();
874 break;
875
877 pListener->drumkitLoadedEvent();
878 break;
879
881 pListener->patternEditorLockedEvent();
882 break;
883
884 case EVENT_RELOCATION:
885 pListener->relocationEvent();
886 break;
887
889 pListener->bbtChangedEvent();
890 break;
891
893 pListener->songSizeChangedEvent();
894 break;
895
897 pListener->driverChangedEvent();
898 break;
899
901 pListener->playbackTrackChangedEvent();
902 break;
903
905 pListener->soundLibraryChangedEvent();
906 break;
907
908 case EVENT_NEXT_SHOT:
909 pListener->nextShotEvent();
910 break;
911
913 pListener->midiMapChangedEvent();
914 break;
915
916 default:
917 ERRORLOG( QString("[onEventQueueTimer] Unhandled event: %1").arg( event.type ) );
918 }
919 }
920
921 }
922
923 // midi notes
924 while( !pQueue->m_addMidiNoteVector.empty() ){
925 std::shared_ptr<Song> pSong = Hydrogen::get_instance()->getSong();
926 auto pInstrument = pSong->getInstrumentList()->
927 get( pQueue->m_addMidiNoteVector[0].m_row );
928
929 // find if a (pitch matching) note is already present
930 Note* pOldNote = pSong->getPatternList()->get( pQueue->m_addMidiNoteVector[0].m_pattern )->
931 find_note( pQueue->m_addMidiNoteVector[0].m_column,
932 pQueue->m_addMidiNoteVector[0].m_column,
933 pInstrument,
934 pQueue->m_addMidiNoteVector[0].nk_noteKeyVal,
935 pQueue->m_addMidiNoteVector[0].no_octaveKeyVal );
936
937 auto pUndoStack = HydrogenApp::get_instance()->m_pUndoStack;
938 pUndoStack->beginMacro( tr( "Input Midi Note" ) );
939 if( pOldNote ) { // note found => remove it
941 pOldNote->get_instrument_id(),
942 pQueue->m_addMidiNoteVector[0].m_pattern,
943 pOldNote->get_length(),
944 pOldNote->get_velocity(),
945 pOldNote->getPan(),
946 pOldNote->get_lead_lag(),
947 pOldNote->get_key(),
948 pOldNote->get_octave(),
949 pOldNote->get_probability(),
950 /*isDelete*/ true,
951 /*hearNote*/ false,
952 /*isMidi*/ false,
953 /*isInstrumentMode*/ false,
954 /*isNoteOff*/ false );
955 pUndoStack->push( action );
956 }
957
958 // add the new note
960 pQueue->m_addMidiNoteVector[0].m_row,
961 pQueue->m_addMidiNoteVector[0].m_pattern,
962 pQueue->m_addMidiNoteVector[0].m_length,
963 pQueue->m_addMidiNoteVector[0].f_velocity,
964 pQueue->m_addMidiNoteVector[0].f_pan,
965 0.0,
966 pQueue->m_addMidiNoteVector[0].nk_noteKeyVal,
967 pQueue->m_addMidiNoteVector[0].no_octaveKeyVal,
968 1.0f,
969 /*isDelete*/ false,
970 /*hearNote*/ false,
971 pQueue->m_addMidiNoteVector[0].b_isMidi,
972 pQueue->m_addMidiNoteVector[0].b_isInstrumentMode,
973 /*isNoteOff*/ false );
974 pUndoStack->push( action );
975 pUndoStack->endMacro();
976 pQueue->m_addMidiNoteVector.erase( pQueue->m_addMidiNoteVector.begin() );
977 }
978}
979
980
982 if ( pListener != nullptr ) {
983 m_eventListenersToAdd.insert( pListener );
984 }
985
986 if ( m_eventListenersToRemove.find( pListener ) !=
988 // Listener was already scheduled to be removed. Last action wins.
989 for ( auto it = m_eventListenersToRemove.begin();
990 it != m_eventListenersToRemove.end(); ) {
991 if ( *it == pListener ) {
992 it = m_eventListenersToRemove.erase( it );
993 break;
994 } else {
995 ++it;
996 }
997 }
998 }
999}
1000
1002 if ( pListener != nullptr ) {
1003 m_eventListenersToRemove.insert( pListener );
1004 }
1005
1006 if ( m_eventListenersToAdd.find( pListener ) !=
1007 m_eventListenersToAdd.end() ) {
1008 for ( auto it = m_eventListenersToAdd.begin();
1009 it != m_eventListenersToAdd.end(); ) {
1010 if ( *it == pListener ) {
1011 it = m_eventListenersToAdd.erase( it );
1012 break;
1013 } else {
1014 ++it;
1015 }
1016 }
1017 }
1018}
1019
1021 for ( const auto& ppEventListener : m_eventListenersToRemove ) {
1022 for ( auto it = m_eventListeners.begin();
1023 it != m_eventListeners.end(); ) {
1024 if ( *it == ppEventListener ) {
1025 it = m_eventListeners.erase( it );
1026 break;
1027 } else {
1028 ++it;
1029 }
1030 }
1031 }
1033
1034 for ( const auto& ppEventListener : m_eventListenersToAdd ) {
1035 m_eventListeners.push_back( ppEventListener );
1036 }
1037 m_eventListenersToAdd.clear();
1038}
1039
1048
1050
1051 QString sPreferencesFilename;
1052
1053 // Local path of the preferences used during session management.
1054 const QString sPreferencesOverwritePath =
1056 if ( sPreferencesOverwritePath.isEmpty() ) {
1057 sPreferencesFilename = Filesystem::usr_config_path();
1058 } else {
1059 sPreferencesFilename = sPreferencesOverwritePath;
1060 }
1061
1062 if ( nValue == 0 ) {
1063 showStatusBarMessage( tr("Preferences saved.") +
1064 QString(" Into: ") + sPreferencesFilename );
1065 } else if ( nValue == 1 ) {
1066
1067 // Since the Preferences have changed, we also have to reflect
1068 // these changes in the GUI - its format, colors, fonts,
1069 // selections etc.
1070 // But we won't change the layout!
1073
1074 WindowProperties audioEngineInfoProp = pPref->getAudioEngineInfoProperties();
1076
1077 // MAINFORM
1078 WindowProperties mainFormProp = pPref->getMainFormProperties();
1079 setWindowProperties( m_pMainForm, mainFormProp );
1080
1081 m_pSplitter->setOrientation( Qt::Vertical );
1082 m_pSplitter->setOpaqueResize( true );
1083
1084 // SONG EDITOR
1085 WindowProperties songEditorProp = pPref->getSongEditorProperties();
1087
1088 // PATTERN EDITOR
1089 WindowProperties patternEditorProp = pPref->getPatternEditorProperties();
1091
1092 WindowProperties instrumentRackProp = pPref->getInstrumentRackProperties();
1093 m_pInstrumentRack->setHidden( !instrumentRackProp.visible );
1094
1095 WindowProperties mixerProp = pPref->getMixerProperties();
1096 if ( layout != InterfaceTheme::Layout::SinglePane ) {
1097 mixerProp.visible = false;
1098 }
1099 setWindowProperties( m_pMixer, mixerProp );
1100
1101 m_pMixer->updateMixer();
1102
1103 WindowProperties playlistDialogProp = pPref->getPlaylistDialogProperties();
1104 setWindowProperties( m_pPlaylistDialog, playlistDialogProp, SetAll );
1105
1106 WindowProperties directorProp = pPref->getDirectorProperties();
1107 setWindowProperties( m_pDirector, directorProp, SetAll );
1108
1109#ifdef H2CORE_HAVE_LADSPA
1110 // LADSPA FX
1111 for (uint nFX = 0; nFX < MAX_FX; nFX++) {
1112 m_pLadspaFXProperties[nFX]->hide();
1113 WindowProperties prop = pPref->getLadspaProperties(nFX);
1114 setWindowProperties( m_pLadspaFXProperties[ nFX ], prop, SetX + SetY );
1115 }
1116#endif
1117
1118 // Inform the user about which file was loaded.
1119 showStatusBarMessage( tr("Preferences loaded.") +
1120 QString(" From: ") + sPreferencesFilename );
1121
1122
1123 } else {
1124 ERRORLOG( QString( "Unknown event parameter [%1] in HydrogenApp::updatePreferencesEvent" )
1125 .arg( nValue ) );
1126 }
1127
1128}
1129
1131
1132 auto pHydrogen = Hydrogen::get_instance();
1133 auto pSong = pHydrogen->getSong();
1134 if ( pSong == nullptr ) {
1135 return;
1136 }
1137
1138 if ( nValue == 0 ) {
1139 // Cleanup
1141 m_pUndoStack->clear();
1142
1143 // Update GUI components
1145
1146 } else if ( nValue == 1 ) {
1147
1148 QString sFilename = pSong->getFilename();
1149
1150 // Song was saved.
1151 showStatusBarMessage( tr("Song saved as: ") + sFilename );
1153
1154 } else if ( nValue == 2 ) {
1155
1156 // The event was triggered before the Song was fully loaded by
1157 // the core. It's most likely to be present by now, but it's
1158 // probably better to avoid displaying its path just to be
1159 // sure.
1160 QMessageBox::information( m_pMainForm, "Hydrogen", tr("Song is read-only.\nUse 'Save as' to enable autosave." ) );
1161 }
1162}
1163
1165 if ( m_pPreferencesUpdateTimer->isActive() ) {
1167 }
1169 // Ensure the provided changes will be propagated too.
1170
1171 if ( ! ( m_bufferedChanges & changes ) ) {
1173
1174 }
1175}
1176
1181
1182bool HydrogenApp::checkDrumkitLicense( std::shared_ptr<H2Core::Drumkit> pDrumkit ) {
1183
1184 auto pPref = H2Core::Preferences::get_instance();
1185
1186 if ( ! pPref->m_bShowExportDrumkitLicenseWarning &&
1187 ! pPref->m_bShowExportDrumkitCopyleftWarning &&
1188 ! pPref->m_bShowExportDrumkitAttributionWarning ) {
1189 return true;
1190 }
1191
1192 auto pCommonStrings = HydrogenApp::get_instance()->getCommonStrings();
1193
1194 auto drumkitLicense = pDrumkit->get_license();
1195 auto contentVector = pDrumkit->summarizeContent();
1196
1197 QStringList additionalLicenses;
1198 bool bCopyleftLicenseFound = drumkitLicense.isCopyleft();
1199 bool bAttributionRequired = drumkitLicense.hasAttribution();
1200
1201 for ( const auto& ccontent : contentVector ) {
1202 QString sSampleLicense = QString( "%1 (by %2)" )
1203 .arg( ccontent->m_license.getLicenseString() )
1204 .arg( ccontent->m_license.getCopyrightHolder() );
1205
1206 if ( ccontent->m_license != drumkitLicense &&
1207 ! additionalLicenses.contains( sSampleLicense ) ) {
1208 additionalLicenses << sSampleLicense;
1209
1210 bCopyleftLicenseFound = bCopyleftLicenseFound ||
1211 ccontent->m_license.isCopyleft();
1212 bAttributionRequired = bAttributionRequired ||
1213 ccontent->m_license.hasAttribution();
1214 }
1215 }
1216
1217 if ( additionalLicenses.size() > 0 &&
1218 pPref->m_bShowExportDrumkitLicenseWarning ) {
1219
1220 QString sMsg = tr( "Some sample licenses deviate from the one assigned to the overall drumkit [%1] and will be overwritten. Are you sure?" )
1221 .arg( drumkitLicense.getLicenseString() );
1222
1223 sMsg.append( "\n" );
1224 for ( const auto& sLicense : additionalLicenses ) {
1225 sMsg.append( QString( "\n- %1" ).arg( sLicense ) );
1226 }
1227
1228 QMessageBox licenseWarning;
1229 licenseWarning.setWindowTitle( pCommonStrings->getLicenseWarningWindowTitle() );
1230 licenseWarning.setText( sMsg );
1231 licenseWarning.addButton( pCommonStrings->getButtonOk(),
1232 QMessageBox::AcceptRole );
1233 auto pMuteButton =
1234 licenseWarning.addButton( pCommonStrings->getMutableDialog(),
1235 QMessageBox::YesRole );
1236 auto pRejectButton =
1237 licenseWarning.addButton( pCommonStrings->getButtonCancel(),
1238 QMessageBox::RejectRole );
1239
1240 licenseWarning.exec();
1241
1242 if ( licenseWarning.clickedButton() == pMuteButton ) {
1243 pPref->m_bShowExportDrumkitLicenseWarning = false;
1244 }
1245 else if ( licenseWarning.clickedButton() == pRejectButton ) {
1246 ERRORLOG( "Aborted on overwriting licenses" );
1247 return false;
1248 }
1249 }
1250
1251 if ( bCopyleftLicenseFound &&
1252 pPref->m_bShowExportDrumkitCopyleftWarning ) {
1253 QMessageBox copyleftWarning;
1254 copyleftWarning.setWindowTitle( pCommonStrings->getLicenseWarningWindowTitle() );
1255 copyleftWarning.setText( pCommonStrings->getLicenseCopyleftWarning() );
1256 copyleftWarning.addButton( pCommonStrings->getButtonOk(),
1257 QMessageBox::AcceptRole );
1258 auto pMuteButton =
1259 copyleftWarning.addButton( pCommonStrings->getMutableDialog(),
1260 QMessageBox::YesRole );
1261 auto pRejectButton =
1262 copyleftWarning.addButton( pCommonStrings->getButtonCancel(),
1263 QMessageBox::RejectRole );
1264
1265 copyleftWarning.exec();
1266
1267 if ( copyleftWarning.clickedButton() == pMuteButton ) {
1268 pPref->m_bShowExportDrumkitCopyleftWarning = false;
1269 }
1270 else if ( copyleftWarning.clickedButton() == pRejectButton ) {
1271 ERRORLOG( "Aborted on copyleft licenses" );
1272 return false;
1273 }
1274 }
1275
1276 if ( bAttributionRequired &&
1277 pPref->m_bShowExportDrumkitAttributionWarning ) {
1278 QMessageBox attributionWarning;
1279 attributionWarning.setWindowTitle( pCommonStrings->getLicenseWarningWindowTitle() );
1280 attributionWarning.setText( pCommonStrings->getLicenseAttributionWarning() );
1281 attributionWarning.addButton( pCommonStrings->getButtonOk(),
1282 QMessageBox::AcceptRole );
1283 auto pMuteButton =
1284 attributionWarning.addButton( pCommonStrings->getMutableDialog(),
1285 QMessageBox::YesRole );
1286 auto pRejectButton =
1287 attributionWarning.addButton( pCommonStrings->getButtonCancel(),
1288 QMessageBox::RejectRole );
1289
1290 attributionWarning.exec();
1291
1292 if ( attributionWarning.clickedButton() == pMuteButton ) {
1293 pPref->m_bShowExportDrumkitAttributionWarning = false;
1294 }
1295 else if ( attributionWarning.clickedButton() == pRejectButton ) {
1296 ERRORLOG( "Aborted on attribution licenses" );
1297 return false;
1298 }
1299 }
1300
1301 return true;
1302}
1303
1307 getMetronomeInstrument()->set_volume(
1308 Preferences::get_instance()->m_fMetronomeVolume );
1309 }
1310}
constexpr uint16_t QUEUE_TIMER_PERIOD
Amount of time to pass between successive calls to HydrogenApp::onEventQueueTimer() in milliseconds.
Definition HydrogenApp.h:47
#define INFOLOG(x)
Definition Object.h:240
#define ERRORLOG(x)
Definition Object.h:242
Audio Engine information form.
static constexpr int m_nMinimumHeight
bool locateToColumn(int nPatternGroup)
Relocates transport to the beginning of a particular column/Pattern group.
Object handling the communication between the core of Hydrogen and its GUI.
Definition EventQueue.h:211
static EventQueue * get_instance()
Returns a pointer to the current EventQueue singleton stored in __instance.
Definition EventQueue.h:224
std::vector< AddMidiNoteVector > m_addMidiNoteVector
Definition EventQueue.h:274
Event pop_event()
Reads out the next event of the EventQueue.
Basic building block for the communication between the core of Hydrogen and its GUI.
Definition EventQueue.h:186
EventType type
Specifies the context the event is create in and which function should be triggered to handle it.
Definition EventQueue.h:190
int value
Additional information to describe the actual context of the engine.
Definition EventQueue.h:193
static QString usr_config_path()
static QString untitled_song_name()
returns untitled song name
static const QString & getPreferencesOverwritePath()
Definition Filesystem.h:590
static bool rm(const QString &path, bool recursive=false, bool bSilent=false)
remove a path
static QString empty_song_path()
Provides the full path to the current empty song.
static QString tmp_dir()
returns temp path
Hydrogen Audio Engine.
Definition Hydrogen.h:54
std::shared_ptr< Song > getSong() const
Get the current song.
Definition Hydrogen.h:123
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:84
AudioEngine * getAudioEngine() const
Definition Hydrogen.h:663
AudioOutput * getAudioOutput() const
Used to display audio driver info.
Definition Hydrogen.cpp:741
CoreActionController * getCoreActionController() const
Definition Hydrogen.h:653
A note plays an associated instrument with a velocity left and right pan.
Definition Note.h:101
int get_position() const
__position accessor
Definition Note.h:534
Octave get_octave()
__octave accessor
Definition Note.h:676
float get_lead_lag() const
__lead_lag accessor
Definition Note.h:549
int get_length() const
__length accessor
Definition Note.h:559
float get_velocity() const
__velocity accessor
Definition Note.h:539
Key get_key()
__key accessor
Definition Note.h:671
float get_probability() const
Definition Note.h:609
float getPan() const
get pan of the note.
Definition Note.h:544
int get_instrument_id() const
__instrument_id accessor
Definition Note.h:514
Manager for User Preferences File (singleton)
Definition Preferences.h:79
WindowProperties getAudioEngineInfoProperties()
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
void setLastOpenTab(int n)
WindowProperties getMainFormProperties()
InterfaceTheme::Layout getDefaultUILayout()
WindowProperties getDirectorProperties()
WindowProperties getMixerProperties()
Changes
Bitwise or-able options showing which part of the Preferences were altered using the PreferencesDialo...
@ AudioTab
Any option in the Audio tab appeared.
WindowProperties getPatternEditorProperties()
WindowProperties getLadspaProperties(unsigned nFX)
WindowProperties getInstrumentRackProperties()
WindowProperties getSongEditorProperties()
WindowProperties getPlaylistDialogProperties()
AudioEngineInfoForm * m_pAudioEngineInfoForm
void updateWindowTitle()
void addEventListener(EventListener *pListener)
static HydrogenApp * get_instance()
Returns the instance of HydrogenApp class.
std::shared_ptr< CommonStrings > getCommonStrings()
std::shared_ptr< CommonStrings > m_pCommonStrings
void updateEventListeners()
InfoBar * addInfoBar()
int m_nPreferencesUpdateTimeout
QUndoStack * m_pUndoStack
Director * m_pDirector
std::vector< EventListener * > m_eventListeners
void showAudioEngineInfoForm()
QSplitter * m_pSplitter
void showFilesystemInfoForm()
QScrollArea * m_pMainScrollArea
Used for accessibility reasons to show scroll bars in case Hydrogen has to be shrunk below its minimu...
SongEditorPanel * m_pSongEditorPanel
InstrumentRack * getInstrumentRack()
void closeFXProperties()
virtual void updatePreferencesEvent(int nValue) override
Handles the loading and saving of the H2Core::Preferences from the core part of H2Core::Hydrogen.
static bool openSong(QString sFilename)
void onPreferencesChanged(H2Core::Preferences::Changes changes)
PlayerControl * m_pPlayerControl
PlaylistDialog * m_pPlaylistDialog
virtual void updateSongEvent(int nValue) override
Refreshes and updates the GUI after the Song was changed in the core part of Hydrogen.
static bool checkDrumkitLicense(std::shared_ptr< H2Core::Drumkit > pDrumkit)
void showDirector()
PatternEditorPanel * m_pPatternEditorPanel
void showStatusBarMessage(const QString &sMessage, const QString &sCaller="")
QVBoxLayout * m_pMainVBox
QTimer * m_pPreferencesUpdateTimer
virtual void drumkitLoadedEvent() override
void showMixer(bool bShow)
void showPlaylistDialog()
void onEventQueueTimer()
Function called every QUEUE_TIMER_PERIOD millisecond to pop all Events from the EventQueue and invoke...
void preferencesChanged(H2Core::Preferences::Changes changes)
Propagates a change in the Preferences through the GUI.
std::set< EventListener * > m_eventListenersToRemove
void changePreferences(H2Core::Preferences::Changes changes)
Propagates a change in the Preferences through the GUI.
QTimer * m_pEventQueueTimer
void showInstrumentPanel(bool)
void showSampleEditor(QString name, int mSelectedComponemt, int mSelectedLayer)
std::set< EventListener * > m_eventListenersToAdd
static bool recoverEmptySong()
Specialized version of openSong( QString sFilename ) trying to open the autosave file corresponding t...
void currentTabChanged(int)
void removeEventListener(EventListener *pListener)
virtual void songModifiedEvent() override
InstrumentRack * m_pInstrumentRack
virtual void XRunEvent() override
H2Core::WindowProperties getWindowProperties(QWidget *pWindow)
virtual ~HydrogenApp()
Mixer * m_pMixer
void showPreferencesDialog()
void cleanupTemporaryFiles()
Removes temporary files that were created for undo'ing things.
H2Core::Preferences::Changes m_bufferedChanges
void setWindowProperties(QWidget *pWindow, H2Core::WindowProperties &prop, unsigned flags=SetAll)
MainForm * m_pMainForm
SampleEditor * m_pSampleEditor
QTabWidget * m_pTab
void setupSinglePanedInterface()
void propagatePreferences()
HydrogenApp(MainForm *pMainForm)
FilesystemInfoForm * m_pFilesystemInfoForm
static HydrogenApp * m_pInstance
HydrogenApp instance.
bool m_bHideKeyboardCursor
static constexpr int m_nMinimumHeight
450 - InstrumentEditor layer view + 24 - tab button
debug only
Definition MainForm.h:47
void onPreferencesChanged(H2Core::Preferences::Changes changes)
Definition Mixer.h:44
Pattern Editor Panel.
static constexpr int m_nMinimumHeight
This dialog is used to use the H2PlayList.
Preferences Dialog.
This dialog is used to preview audiofiles.
static constexpr int m_nMinimumHeight
static constexpr int m_nMinimumHeight
Definition SongEditor.h:393
static constexpr int m_nMinimumHeight
Default value of Preferences::m_nSongEditorGridHeight * 5 (patterns)
Definition SongEditor.h:109
#define MAX_FX
Maximum number of effects.
Definition config.dox:83
@ EVENT_RELOCATION
Triggered in case there is a relocation of the transport position while trasnsport is not rolling.
Definition EventQueue.h:166
@ EVENT_XRUN
Definition EventQueue.h:85
@ EVENT_PLAYBACK_TRACK_CHANGED
Definition EventQueue.h:175
@ EVENT_INSTRUMENT_PARAMETERS_CHANGED
Some parameters of an instrument have been changed.
Definition EventQueue.h:83
@ EVENT_METRONOME
Triggered when a metronome note is passed to the H2Core::Sampler.
Definition EventQueue.h:97
@ EVENT_UNDO_REDO
Definition EventQueue.h:101
@ EVENT_PLAYLIST_LOADSONG
Definition EventQueue.h:100
@ EVENT_DRUMKIT_LOADED
A the current drumkit was replaced by a new one.
Definition EventQueue.h:158
@ EVENT_STATE
Definition EventQueue.h:43
@ EVENT_JACK_TRANSPORT_ACTIVATION
Toggles the button indicating the usage JACK transport.
Definition EventQueue.h:141
@ EVENT_PLAYING_PATTERNS_CHANGED
The list of currently played patterns (AudioEngine::getPlayingPatterns()) did change.
Definition EventQueue.h:57
@ EVENT_TEMPO_CHANGED
Definition EventQueue.h:103
@ EVENT_ACTION_MODE_CHANGE
Switches between select mode (0) and draw mode (1) in the *SongEditor.
Definition EventQueue.h:152
@ EVENT_SELECTED_INSTRUMENT_CHANGED
Definition EventQueue.h:77
@ EVENT_PATTERN_MODIFIED
A pattern was added, deleted, or modified.
Definition EventQueue.h:68
@ EVENT_TIMELINE_ACTIVATION
Enables/disables the usage of the Timeline.
Definition EventQueue.h:136
@ EVENT_SOUND_LIBRARY_CHANGED
Definition EventQueue.h:176
@ EVENT_TIMELINE_UPDATE
Tells the GUI some parts of the Timeline (tempo markers or tags) were modified.
Definition EventQueue.h:139
@ EVENT_NEXT_SHOT
Definition EventQueue.h:177
@ EVENT_SONG_SIZE_CHANGED
Definition EventQueue.h:173
@ EVENT_UPDATE_SONG
Event triggering HydrogenApp::updateSongEvent() whenever the Song was changed outside of the GUI,...
Definition EventQueue.h:128
@ EVENT_BBT_CHANGED
The coarse grained transport position in beats and bars did change.
Definition EventQueue.h:172
@ EVENT_LOOP_MODE_ACTIVATION
Toggles the button indicating the usage loop mode.
Definition EventQueue.h:150
@ EVENT_NOTEON
Definition EventQueue.h:86
@ EVENT_MIDI_ACTIVITY
Definition EventQueue.h:84
@ EVENT_MIDI_MAP_CHANGED
Definition EventQueue.h:178
@ EVENT_GRID_CELL_TOGGLED
Definition EventQueue.h:153
@ EVENT_NONE
Fallback event.
Definition EventQueue.h:42
@ EVENT_NEXT_PATTERNS_CHANGED
Used in Song::PatternMode::Stacked to indicate that a either AudioEngine::getNextPatterns() did chang...
Definition EventQueue.h:64
@ EVENT_SONG_MODIFIED
Definition EventQueue.h:102
@ EVENT_QUIT
Triggering HydrogenApp::quitEvent() and enables a shutdown of the entire application via the command ...
Definition EventQueue.h:133
@ EVENT_PROGRESS
Definition EventQueue.h:98
@ EVENT_ERROR
Definition EventQueue.h:87
@ EVENT_UPDATE_PREFERENCES
Event triggering the loading or saving of the H2Core::Preferences whenever they were changed outside ...
Definition EventQueue.h:116
@ EVENT_JACK_TIMEBASE_STATE_CHANGED
Toggles the button indicating the usage JACK Timebase control and informs the GUI about a state chang...
Definition EventQueue.h:144
@ EVENT_PATTERN_EDITOR_LOCKED
Locks the PatternEditor on the pattern currently played back.
Definition EventQueue.h:160
@ EVENT_JACK_SESSION
Definition EventQueue.h:99
@ EVENT_SONG_MODE_ACTIVATION
Definition EventQueue.h:145
@ EVENT_SELECTED_PATTERN_CHANGED
Another pattern was selected via MIDI or the GUI without affecting the audio transport.
Definition EventQueue.h:76
@ EVENT_DRIVER_CHANGED
Definition EventQueue.h:174
@ EVENT_STACKED_MODE_ACTIVATION
Song::PatternMode::Stacked (0) or Song::PatternMode::Selected (1) was activated.
Definition EventQueue.h:148
std::string get_version()
Returns the current Hydrogen version string.
Definition Version.cpp:30