hydrogen 1.2.3
Hydrogen.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-2024 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#include <core/config.h>
23
24#ifdef WIN32
25# include "core/Timehelper.h"
26#else
27# include <unistd.h>
28# include <sys/time.h>
29#endif
30
31
32#include <pthread.h>
33#include <cassert>
34#include <cstdio>
35#include <deque>
36#include <queue>
37#include <iostream>
38#include <cmath>
39#include <algorithm>
40#include <thread>
41#include <chrono>
42
43#include <QtCore/QMutex>
44#include <QtCore/QMutexLocker>
45
46#include <core/EventQueue.h>
47#include <core/Basics/Adsr.h>
48#include <core/Basics/Drumkit.h>
50#include <core/H2Exception.h>
58#include <core/Basics/Sample.h>
60#include <core/Hydrogen.h>
61#include <core/Basics/Pattern.h>
63#include <core/Basics/Note.h>
65#include <core/FX/LadspaFX.h>
66#include <core/FX/Effects.h>
68
71#include "MidiMap.h"
72
73#ifdef H2CORE_HAVE_OSC
74#include <core/NsmClient.h>
75#include "OscServer.h"
76#endif
77
78#include <core/IO/AudioOutput.h>
80#include <core/IO/NullDriver.h>
81#include <core/IO/MidiInput.h>
82#include <core/IO/MidiOutput.h>
84#include <core/IO/OssDriver.h>
85#include <core/IO/FakeDriver.h>
94
95namespace H2Core
96{
97//----------------------------------------------------------------------------
98//
99// Implementation of Hydrogen class
100//
101//----------------------------------------------------------------------------
102
103Hydrogen* Hydrogen::__instance = nullptr;
104
105Hydrogen::Hydrogen() : m_nSelectedInstrumentNumber( 0 )
106 , m_nSelectedPatternNumber( 0 )
107 , m_bExportSessionIsActive( false )
108 , m_GUIState( GUIState::unavailable )
109 , m_lastMidiEvent( MidiMessage::Event::Null )
110 , m_nLastMidiEventParameter( 0 )
111 , m_CurrentTime( {0,0} )
112 , m_oldEngineMode( Song::Mode::Song )
113 , m_bOldLoopEnabled( false )
114 , m_nLastRecordedMIDINoteTick( 0 )
115 , m_bSessionDrumkitNeedsRelinking( false )
116 , m_bSessionIsExported( false )
117{
118 if ( __instance ) {
119 ERRORLOG( "Hydrogen audio engine is already running" );
120 throw H2Exception( "Hydrogen audio engine is already running" );
121 }
122
123 INFOLOG( "[Hydrogen]" );
124
125 __song = nullptr;
126
127 m_pTimeline = std::make_shared<Timeline>();
128 m_pCoreActionController = new CoreActionController();
129
130 initBeatcounter();
132
133 m_pAudioEngine = new AudioEngine();
135
137
138 // Prevent double creation caused by calls from MIDI thread
139 __instance = this;
140
141 m_pAudioEngine->startAudioDrivers();
142
143 for(int i = 0; i< MAX_INSTRUMENTS; i++){
144 m_nInstrumentLookupTable[i] = i;
145 }
146
147 if ( Preferences::get_instance()->getOscServerEnabled() ) {
148 toggleOscServer( true );
149 }
150
151 m_pSoundLibraryDatabase = new SoundLibraryDatabase();
152}
153
155{
156 INFOLOG( "[~Hydrogen]" );
157
158#ifdef H2CORE_HAVE_OSC
159 NsmClient* pNsmClient = NsmClient::get_instance();
160 if( pNsmClient ) {
161 pNsmClient->shutdown();
162 delete pNsmClient;
163 }
164 OscServer* pOscServer = OscServer::get_instance();
165 if( pOscServer ) {
166 delete pOscServer;
167 }
168#endif
169
170 removeSong();
171
173
176 delete m_pAudioEngine;
177
178 __instance = nullptr;
179}
180
182{
183 // Create all the other instances that we need
184 // ....and in the right order
190
191#ifdef H2CORE_HAVE_OSC
194#endif
195
196 if ( __instance == nullptr ) {
197 __instance = new Hydrogen;
198 }
199
200 // See audioEngine_init() for:
201 // AudioEngine::create_instance();
202 // Effects::create_instance();
203 // Playlist::create_instance();
204}
205
216
219{
220 std::shared_ptr<Song> pSong = getSong();
221 pSong->getPatternList()->set_to_old();
223}
224
227{
228 if( Hydrogen::get_instance()->getMidiOutput() != nullptr ){
230 }
231
234
235 // Delete redundant instruments still alive after switching the
236 // drumkit to a smaller one.
238}
239
241
242 if ( __song == nullptr ) {
243 ERRORLOG( "No song set yet" );
245 }
246
247 return __song->getPlaybackTrackState();
248}
249
250void Hydrogen::mutePlaybackTrack( const bool bMuted )
251{
252 if ( __song == nullptr ) {
253 ERRORLOG( "No song set yet" );
254 return;
255 }
256
257 __song->setPlaybackTrackEnabled( bMuted );
258
260}
261
262void Hydrogen::loadPlaybackTrack( QString sFilename )
263{
264 if ( __song == nullptr ) {
265 ERRORLOG( "No song set yet" );
266 return;
267 }
268
269 if ( ! sFilename.isEmpty() &&
270 ! Filesystem::file_exists( sFilename, true ) ) {
271 ERRORLOG( QString( "Invalid playback track filename [%1]. File does not exist." )
272 .arg( sFilename ) );
273 sFilename = "";
274 }
275
276 if ( sFilename.isEmpty() ) {
277 INFOLOG( "Disable playback track" );
278 __song->setPlaybackTrackEnabled( false );
279 }
280
281 __song->setPlaybackTrackFilename( sFilename );
282
284
286}
287
288void Hydrogen::setSong( std::shared_ptr<Song> pSong, bool bRelinking )
289{
290 assert ( pSong );
291
292 // Move to the beginning.
294
295 std::shared_ptr<Song> pCurrentSong = getSong();
296 if ( pSong == pCurrentSong ) {
297 return;
298 }
299
300 if ( pCurrentSong != nullptr ) {
301 /* NOTE:
302 * - this is actually some kind of cleanup
303 * - removeSong cares itself for acquiring a lock
304 */
305
306 if ( isUnderSessionManagement() ) {
307 // When under session management Hydrogen is only allowed
308 // to replace the content of the session song but not to
309 // write to a different location.
310 pSong->setFilename( pCurrentSong->getFilename() );
311 }
312 removeSong();
313 }
314
315 // In order to allow functions like audioEngine_setupLadspaFX() to
316 // load the settings of the new song, like whether the LADSPA FX
317 // are activated, __song has to be set prior to the call of
318 // audioEngine_setSong().
319 __song = pSong;
320
321 // Ensure the selected instrument is within the range of new
322 // instrument list.
323 if ( m_nSelectedInstrumentNumber >= __song->getInstrumentList()->size() ) {
325 std::max( __song->getInstrumentList()->size() - 1, 0 );
326 }
327
328 // Update the audio engine to work with the new song.
329 m_pAudioEngine->setSong( pSong );
330
331 // load new playback track information
333
334 // Push current state of Hydrogen to attached control interfaces,
335 // like OSC clients.
337
338#ifdef H2CORE_HAVE_OSC
339 if ( isUnderSessionManagement() && bRelinking ) {
341 }
342#endif
343}
344
345/* Mean: remove current song from memory */
347{
349 __song = nullptr;
350}
351
353{
354 m_pAudioEngine->noteOn( note );
355}
356
357void Hydrogen::addRealtimeNote( int nInstrument,
358 float fVelocity,
359 float fPan,
360 bool bNoteOff,
361 int nNote )
362{
363
364 AudioEngine* pAudioEngine = m_pAudioEngine;
365 auto pSampler = pAudioEngine->getSampler();
367 unsigned int nRealColumn = 0;
368 unsigned res = pPref->getPatternEditorGridResolution();
369 int nBase = pPref->isPatternEditorUsingTriplets() ? 3 : 4;
370 bool bPlaySelectedInstrument = pPref->__playselectedinstrument;
371 int scalar = ( 4 * MAX_NOTES ) / ( res * nBase );
372 int currentPatternNumber;
373
374 std::shared_ptr<Song> pSong = getSong();
375
376 if ( pSong == nullptr ) {
377 ERRORLOG( "No song set yet" );
378 return;
379 }
380
382
383 if ( ! bPlaySelectedInstrument ) {
384 if ( nInstrument >= ( int ) pSong->getInstrumentList()->size() ) {
385 // unused instrument
386 ERRORLOG( QString( "Provided instrument [%1] not found" )
387 .arg( nInstrument ) );
388 pAudioEngine->unlock();
389 return;
390 }
391 }
392
393 // Get current pattern and column
394 const Pattern* pCurrentPattern = nullptr;
395 long nTickInPattern = 0;
396
397 bool doRecord = pPref->getRecordEvents();
398 if ( getMode() == Song::Mode::Song && doRecord &&
399 pAudioEngine->getState() == AudioEngine::State::Playing ) {
400
401 // Recording + song playback mode + actually playing
402 PatternList* pPatternList = pSong->getPatternList();
403 auto pColumns = pSong->getPatternGroupVector();
404 int nColumn = pAudioEngine->getTransportPosition()->getColumn(); // current column
405 // or pattern group
406 if ( nColumn < 0 || nColumn >= pColumns->size() ) {
407 pAudioEngine->unlock(); // unlock the audio engine
408 ERRORLOG( QString( "Provided column [%1] out of bound [%2,%3)" )
409 .arg( nColumn ).arg( 0 )
410 .arg( pColumns->size() ) );
411 return;
412 }
413 // Locate nTickInPattern -- may need to jump back one column
414 nTickInPattern = pAudioEngine->getTransportPosition()->getPatternTickPosition();
415
416 // Capture new notes in the bottom-most pattern (if not already done above)
417 PatternList *pColumn = ( *pColumns )[ nColumn ];
418 currentPatternNumber = -1;
419 for ( int n = 0; n < pColumn->size(); n++ ) {
420 Pattern *pPattern = pColumn->get( n );
421 int nIndex = pPatternList->index( pPattern );
422 if ( nIndex > currentPatternNumber ) {
423 currentPatternNumber = nIndex;
424 pCurrentPattern = pPattern;
425 }
426 }
427
428 // Cancel recording if punch area disagrees
429 doRecord = pPref->inPunchArea( nColumn );
430
431 }
432 else { // Not song-record mode
433 PatternList *pPatternList = pSong->getPatternList();
434
435 if ( ( m_nSelectedPatternNumber != -1 )
436 && ( m_nSelectedPatternNumber < ( int )pPatternList->size() ) )
437 {
438 pCurrentPattern = pPatternList->get( m_nSelectedPatternNumber );
439 currentPatternNumber = m_nSelectedPatternNumber;
440 }
441
442 if ( ! pCurrentPattern ) {
443 ERRORLOG( "Current pattern invalid" );
444 pAudioEngine->unlock(); // unlock the audio engine
445 return;
446 }
447
448 // Locate nTickInPattern -- may need to wrap around end of pattern
449 nTickInPattern = pAudioEngine->getTransportPosition()->getPatternTickPosition();
450 }
451
452 if ( pCurrentPattern && pPref->getQuantizeEvents() ) {
453 // quantize it to scale
454 unsigned qcolumn = ( unsigned )::round( nTickInPattern / ( double )scalar ) * scalar;
455
456 //we have to make sure that no beat is added on the last displayed note in a bar
457 //for example: if the pattern has 4 beats, the editor displays 5 beats, so we should avoid adding beats an note 5.
458 if ( qcolumn == pCurrentPattern->get_length() ){
459 qcolumn = 0;
460 }
461 nTickInPattern = qcolumn;
462 }
463
464 auto pInstrumentList = pSong->getInstrumentList();
465 int nInstrumentNumber;
466 if ( bPlaySelectedInstrument ) {
467 nInstrumentNumber = getSelectedInstrumentNumber();
468 } else {
469 nInstrumentNumber = m_nInstrumentLookupTable[ nInstrument ];
470 }
471 auto pInstr = pInstrumentList->get( nInstrumentNumber );
472 if ( pInstr == nullptr ) {
473 ERRORLOG( QString( "Unable to retrieved instrument [%1]. Plays selected instrument: [%2]" )
474 .arg( nInstrumentNumber )
475 .arg( bPlaySelectedInstrument ) );
476 pAudioEngine->unlock();
477 return;
478 }
479
480 // Record note
481 if ( pCurrentPattern != nullptr &&
482 pAudioEngine->getState() == AudioEngine::State::Playing &&
483 doRecord ) {
484
485 INFOLOG( QString( "Recording [%1] to pattern: %2 (%3), tick: [%4/%5]." )
486 .arg( bNoteOff ? "NoteOff" : "NoteOn")
487 .arg( currentPatternNumber ).arg( pCurrentPattern->get_name() )
488 .arg( nTickInPattern ).arg( pCurrentPattern->get_length() ) );
489
490 bool bIsModified = false;
491
492 if ( bNoteOff ) {
493
494 int nPatternSize = pCurrentPattern->get_length();
495 int nNoteLength =
496 static_cast<int>(pAudioEngine->getTransportPosition()->getPatternTickPosition()) -
498
499 if ( bPlaySelectedInstrument ) {
500 nNoteLength =
501 static_cast<int>(static_cast<double>(nNoteLength) *
502 Note::pitchToFrequency( nNote ));
503 }
504
505 for ( unsigned nNote = 0; nNote < nPatternSize; nNote++ ) {
506 const Pattern::notes_t* notes = pCurrentPattern->get_notes();
507 FOREACH_NOTE_CST_IT_BOUND_LENGTH( notes, it, nNote, pCurrentPattern ) {
508 Note *pNote = it->second;
509 if ( pNote != nullptr &&
511 pInstr == pNote->get_instrument() ) {
512
513 if ( m_nLastRecordedMIDINoteTick + nNoteLength > nPatternSize ) {
514 nNoteLength = nPatternSize - m_nLastRecordedMIDINoteTick;
515 }
516 pNote->set_length( nNoteLength );
517 bIsModified = true;
518 }
519 }
520 }
521
522 }
523 else { // note on
525 noteAction.m_column = nTickInPattern;
526 noteAction.m_row = nInstrumentNumber;
527 noteAction.m_pattern = currentPatternNumber;
528 noteAction.f_velocity = fVelocity;
529 noteAction.f_pan = fPan;
530 noteAction.m_length = -1;
531 noteAction.b_isMidi = true;
532
533 if ( bPlaySelectedInstrument ) {
534 int divider = nNote / 12;
535 noteAction.no_octaveKeyVal = (Note::Octave)(divider -3);
536 noteAction.nk_noteKeyVal = (Note::Key)(nNote - (12 * divider));
537 noteAction.b_isInstrumentMode = true;
538 } else {
539 noteAction.no_octaveKeyVal = (Note::Octave)0;
540 noteAction.nk_noteKeyVal = (Note::Key)0;
541 noteAction.b_isInstrumentMode = false;
542 }
543
544 EventQueue::get_instance()->m_addMidiNoteVector.push_back(noteAction);
545
546 m_nLastRecordedMIDINoteTick = nTickInPattern;
547
548 bIsModified = true;
549 }
550
551 if ( bIsModified ) {
553 setIsModified( true );
554 }
555 }
556
557 // Play back the note.
558 if ( ! pInstr->hasSamples() ) {
559 pAudioEngine->unlock();
560 return;
561 }
562
563 if ( bPlaySelectedInstrument ) {
564 if ( bNoteOff ) {
565 if ( pSampler->isInstrumentPlaying( pInstr ) ) {
566 pSampler->midiKeyboardNoteOff( nNote );
567 }
568 }
569 else { // note on
570 Note *pNote2 = new Note( pInstr, nRealColumn, fVelocity, fPan );
571
572 int divider = nNote / 12;
573 Note::Octave octave = (Note::Octave)(divider -3);
574 Note::Key notehigh = (Note::Key)(nNote - (12 * divider));
575
576 pNote2->set_midi_info( notehigh, octave, nNote );
577 midi_noteOn( pNote2 );
578 }
579 }
580 else {
581 if ( bNoteOff ) {
582 if ( pSampler->isInstrumentPlaying( pInstr ) ) {
583 Note *pNoteOff = new Note( pInstr );
584 pNoteOff->set_note_off( true );
585 midi_noteOn( pNoteOff );
586 }
587 }
588 else { // note on
589 Note *pNote2 = new Note( pInstr, nRealColumn, fVelocity, fPan );
590 midi_noteOn( pNote2 );
591 }
592 }
593
594 m_pAudioEngine->unlock(); // unlock the audio engine
595}
596
597
598void Hydrogen::toggleNextPattern( int nPatternNumber ) {
599 if ( __song != nullptr && getMode() == Song::Mode::Pattern ) {
601 m_pAudioEngine->toggleNextPattern( nPatternNumber );
604
605 } else {
606 ERRORLOG( "can't set next pattern in song mode" );
607 }
608}
609
610bool Hydrogen::flushAndAddNextPattern( int nPatternNumber ) {
611 if ( __song != nullptr && getMode() == Song::Mode::Pattern ) {
613 m_pAudioEngine->flushAndAddNextPattern( nPatternNumber );
616
617 return true;
618
619 } else {
620 ERRORLOG( "can't set next pattern in song mode" );
621 }
622
623 return false;
624}
625
630
631bool Hydrogen::startExportSession( int nSampleRate, int nSampleDepth )
632{
633 AudioEngine* pAudioEngine = m_pAudioEngine;
634
635 if ( pAudioEngine->getState() == AudioEngine::State::Playing ) {
637 }
638
639 std::shared_ptr<Song> pSong = getSong();
640 if ( pSong == nullptr ) {
641 ERRORLOG( "No song set yet" );
642 return false;
643 }
644
645 m_oldEngineMode = pSong->getMode();
646 m_bOldLoopEnabled = pSong->isLoopEnabled();
647
648 pSong->setMode( Song::Mode::Song );
649 pSong->setLoopMode( Song::LoopMode::Disabled );
650
651 /*
652 * Currently an audio driver is loaded
653 * which is not the DiskWriter driver.
654 * Stop the current driver and fire up the DiskWriter.
655 */
656 pAudioEngine->stopAudioDrivers();
657
658 AudioOutput* pDriver =
659 pAudioEngine->createAudioDriver( "DiskWriterDriver" );
660
661 DiskWriterDriver* pDiskWriterDriver = dynamic_cast<DiskWriterDriver*>( pDriver );
662 if ( pDriver == nullptr || pDiskWriterDriver == nullptr ) {
663 ERRORLOG( "Unable to start up DiskWriterDriver" );
664
665 if ( pDriver != nullptr ) {
666 delete pDriver;
667 }
668 return false;
669 }
670
671 pDiskWriterDriver->setSampleRate( static_cast<unsigned>(nSampleRate) );
672 pDiskWriterDriver->setSampleDepth( nSampleDepth );
673
675
676 return true;
677}
678
680void Hydrogen::startExportSong( const QString& filename)
681{
682 AudioEngine* pAudioEngine = m_pAudioEngine;
684 pAudioEngine->play();
685 pAudioEngine->getSampler()->stopPlayingNotes();
686
687 DiskWriterDriver* pDiskWriterDriver = static_cast<DiskWriterDriver*>(pAudioEngine->getAudioDriver());
688 pDiskWriterDriver->setFileName( filename );
689 pDiskWriterDriver->write();
690}
691
693{
694 AudioEngine* pAudioEngine = m_pAudioEngine;
695 pAudioEngine->getSampler()->stopPlayingNotes();
697}
698
700{
701 std::shared_ptr<Song> pSong = getSong();
702 pSong->setMode( m_oldEngineMode );
703 if ( m_bOldLoopEnabled ) {
704 pSong->setLoopMode( Song::LoopMode::Enabled );
705 } else {
706 pSong->setLoopMode( Song::LoopMode::Disabled );
707 }
708
709 AudioEngine* pAudioEngine = m_pAudioEngine;
710
711 pAudioEngine->restartAudioDrivers();
712 if ( pAudioEngine->getAudioDriver() == nullptr ) {
713 ERRORLOG( "Unable to restart previous audio driver after exporting song." );
714 }
716}
717
723
729
734
735// This will check if an instrument has any notes
736bool Hydrogen::instrumentHasNotes( std::shared_ptr<Instrument> pInst )
737{
738 std::shared_ptr<Song> pSong = getSong();
739 PatternList* pPatternList = pSong->getPatternList();
740
741 for ( int nPattern = 0 ; nPattern < (int)pPatternList->size() ; ++nPattern )
742 {
743 if( pPatternList->get( nPattern )->references( pInst ) )
744 {
745 INFOLOG("Instrument " + pInst->get_name() + " has notes" );
746 return true;
747 }
748 }
749
750 // no notes for this instrument
751 return false;
752}
753
754void Hydrogen::removeInstrument( int nInstrumentNumber ) {
755 auto pSong = getSong();
756 if ( pSong != nullptr ) {
757
759
760 pSong->removeInstrument( nInstrumentNumber, false );
761
762 if ( nInstrumentNumber == m_nSelectedInstrumentNumber ) {
763 setSelectedInstrumentNumber( std::max( 0, nInstrumentNumber - 1 ) );
764 } else if ( m_nSelectedInstrumentNumber >=
765 pSong->getInstrumentList()->size() ) {
766 setSelectedInstrumentNumber( std::max( 0, pSong->getInstrumentList()->size() - 1 ) );
767 }
769
770 setIsModified( true );
771 }
772}
773
774void Hydrogen::raiseError( unsigned nErrorCode )
775{
776 m_pAudioEngine->raiseError( nErrorCode );
777}
778
780{
781#ifndef WIN32
782 INFOLOG( "tap tempo" );
783 static timeval oldTimeVal;
784
785 struct timeval now;
786 gettimeofday(&now, nullptr);
787
788 float fInterval =
789 (now.tv_sec - oldTimeVal.tv_sec) * 1000.0
790 + (now.tv_usec - oldTimeVal.tv_usec) / 1000.0;
791
792 oldTimeVal = now;
793
794 // We multiply by a factor of two in order to allow for tempi
795 // smaller than the minimum one enter the calculation of the
796 // average. Else the minimum one could not be reached via tap
797 // tempo and it is clambed anyway.
798 if ( fInterval < 60000.0 * 2 / static_cast<float>(MIN_BPM) ) {
799 setTapTempo( fInterval );
800 }
801#endif
802}
803
804void Hydrogen::setTapTempo( float fInterval )
805{
806
807 // infoLog( "set tap tempo" );
808 static float fOldBpm1 = -1;
809 static float fOldBpm2 = -1;
810 static float fOldBpm3 = -1;
811 static float fOldBpm4 = -1;
812 static float fOldBpm5 = -1;
813 static float fOldBpm6 = -1;
814 static float fOldBpm7 = -1;
815 static float fOldBpm8 = -1;
816
817 float fBPM = 60000.0 / fInterval;
818
819 if ( fabs( fOldBpm1 - fBPM ) > 20 ) { // troppa differenza, niente media
820 fOldBpm1 = fBPM;
821 fOldBpm2 = fBPM;
822 fOldBpm3 = fBPM;
823 fOldBpm4 = fBPM;
824 fOldBpm5 = fBPM;
825 fOldBpm6 = fBPM;
826 fOldBpm7 = fBPM;
827 fOldBpm8 = fBPM;
828 }
829
830 if ( fOldBpm1 == -1 ) {
831 fOldBpm1 = fBPM;
832 fOldBpm2 = fBPM;
833 fOldBpm3 = fBPM;
834 fOldBpm4 = fBPM;
835 fOldBpm5 = fBPM;
836 fOldBpm6 = fBPM;
837 fOldBpm7 = fBPM;
838 fOldBpm8 = fBPM;
839 }
840
841 fBPM = ( fBPM + fOldBpm1 + fOldBpm2 + fOldBpm3 + fOldBpm4 + fOldBpm5
842 + fOldBpm6 + fOldBpm7 + fOldBpm8 ) / 9.0;
843
844 INFOLOG( QString( "avg BPM = %1" ).arg( fBPM ) );
845 fOldBpm8 = fOldBpm7;
846 fOldBpm7 = fOldBpm6;
847 fOldBpm6 = fOldBpm5;
848 fOldBpm5 = fOldBpm4;
849 fOldBpm4 = fOldBpm3;
850 fOldBpm3 = fOldBpm2;
851 fOldBpm2 = fOldBpm1;
852 fOldBpm1 = fBPM;
853
855 m_pAudioEngine->setNextBpm( fBPM );
857
858 // Store it's value in the .h2song file.
859 getSong()->setBpm( fBPM );
860
862}
863
865{
866 AudioEngine* pAudioEngine = m_pAudioEngine;
867
868 if ( pAudioEngine->getAudioDriver() ) {
869 pAudioEngine->lock( RIGHT_HERE );
870 pAudioEngine->setupLadspaFX();
871 pAudioEngine->unlock();
872 } else {
873 ERRORLOG( "m_pAudioDriver = NULL" );
874 }
875}
876
877void Hydrogen::updateSelectedPattern( bool bNeedsLock ) {
878 if ( isPatternEditorLocked() ) {
879 if ( bNeedsLock ) {
881 }
883 if ( bNeedsLock ) {
885 }
886 }
887}
888
889void Hydrogen::setSelectedPatternNumber( int nPat, bool bNeedsLock, bool bForce )
890{
891 if ( nPat == m_nSelectedPatternNumber ) {
892 if ( bForce ) {
894 }
895 return;
896 }
897
899 if ( bNeedsLock ) {
901 }
902
904 // The specific values provided are not important since we a
905 // in selected pattern mode.
907
908 if ( bNeedsLock ) {
910 }
911 } else {
913 }
914
916}
917
918void Hydrogen::setSelectedInstrumentNumber( int nInstrument, bool bTriggerEvent )
919{
920 if ( m_nSelectedInstrumentNumber == nInstrument ) {
921 return;
922 }
923
924 m_nSelectedInstrumentNumber = nInstrument;
925
926 if ( bTriggerEvent ) {
928 }
929}
930
931void Hydrogen::renameJackPorts( std::shared_ptr<Song> pSong )
932{
933#ifdef H2CORE_HAVE_JACK
934 if ( pSong == nullptr ) {
935 return;
936 }
937
938 if( Preferences::get_instance()->m_bJackTrackOuts == true ){
939 if ( hasJackAudioDriver() && pSong != nullptr ) {
940
941 // When restarting the audio driver after loading a new song under
942 // Non session management all ports have to be registered _prior_
943 // to the activation of the client.
946 return;
947 }
948 auto pAudioEngine = m_pAudioEngine;
949
950 static_cast< JackAudioDriver* >( m_pAudioEngine->getAudioDriver() )->makeTrackOutputs( pSong );
951 }
952 }
953#endif
954}
955
958void Hydrogen::setbeatsToCount( int beatstocount)
959{
960 m_nbeatsToCount = beatstocount;
961}
964{
965 return m_nbeatsToCount;
966}
967
968void Hydrogen::setNoteLength( float notelength)
969{
970 m_ntaktoMeterCompute = notelength;
971}
972
974{
976}
977
979{
980 return m_nEventCount;
981}
982
984{
985 //individual fine tuning for the m_nBeatCounter
986 //to adjust ms_offset from different people and controller
987 Preferences *pPreferences = Preferences::get_instance();
988
989 m_nCoutOffset = pPreferences->m_countOffset;
990 m_nStartOffset = pPreferences->m_startOffset;
991}
992
994{
995 AudioEngine* pAudioEngine = m_pAudioEngine;
996
997 // Get first time value:
998 if (m_nBeatCount == 1) {
999 gettimeofday(&m_CurrentTime,nullptr);
1000 }
1001
1002 m_nEventCount++;
1003
1004 // Set lastTime to m_CurrentTime to remind the time:
1005 timeval lastTime = m_CurrentTime;
1006
1007 // Get new time:
1008 gettimeofday(&m_CurrentTime,nullptr);
1009
1010
1011 // Build doubled time difference:
1012 double lastBeatTime = (double)(
1013 lastTime.tv_sec
1014 + (double)(lastTime.tv_usec * US_DIVIDER)
1015 + (int)m_nCoutOffset * .0001
1016 );
1017 double currentBeatTime = (double)(
1018 m_CurrentTime.tv_sec
1019 + (double)(m_CurrentTime.tv_usec * US_DIVIDER)
1020 );
1021 double beatDiff = m_nBeatCount == 1 ? 0 : currentBeatTime - lastBeatTime;
1022
1023 //if differences are to big reset the beatconter
1024 if( beatDiff > 3.001 * 1/m_ntaktoMeterCompute ) {
1025 m_nEventCount = 1;
1026 m_nBeatCount = 1;
1027 return false;
1028 }
1029 // Only accept differences big enough
1030 if (m_nBeatCount == 1 || beatDiff > .001) {
1031 if (m_nBeatCount > 1) {
1032 m_nBeatDiffs[m_nBeatCount - 2] = beatDiff ;
1033 }
1034 // Compute and reset:
1036 double beatTotalDiffs = 0;
1037 for(int i = 0; i < (m_nbeatsToCount - 1); i++) {
1038 beatTotalDiffs += m_nBeatDiffs[i];
1039 }
1040 double nBeatDiffAverage =
1041 beatTotalDiffs
1042 / (m_nBeatCount - 1)
1044 float fBeatCountBpm =
1045 (float) ((int) (60 / nBeatDiffAverage * 100))
1046 / 100;
1047
1048
1050 m_pAudioEngine->setNextBpm( fBeatCountBpm );
1052
1053 getSong()->setBpm( fBeatCountBpm );
1054
1056
1057 if (Preferences::get_instance()->m_mmcsetplay
1059 m_nBeatCount = 1;
1060 m_nEventCount = 1;
1061 } else {
1062 if ( pAudioEngine->getState() != AudioEngine::State::Playing ){
1063 unsigned bcsamplerate =
1064 pAudioEngine->getAudioDriver()->getSampleRate();
1065 unsigned long rtstartframe = 0;
1066 if ( m_ntaktoMeterCompute <= 1){
1067 rtstartframe =
1068 bcsamplerate
1069 * nBeatDiffAverage
1070 * ( 1/ m_ntaktoMeterCompute );
1071 }else
1072 {
1073 rtstartframe =
1074 bcsamplerate
1075 * nBeatDiffAverage
1077 }
1078
1079 int sleeptime =
1080 ( (float) rtstartframe
1081 / (float) bcsamplerate
1082 * (int) 1000 )
1083 + (int)m_nCoutOffset
1084 + (int) m_nStartOffset;
1085
1086 std::this_thread::sleep_for( std::chrono::milliseconds( sleeptime ) );
1087
1089 }
1090
1091 m_nBeatCount = 1;
1092 m_nEventCount = 1;
1093 return true;
1094 }
1095 }
1096 else {
1097 m_nBeatCount ++;
1098 }
1099 }
1100 else {
1101 return false;
1102 }
1103 return true;
1104}
1105// ~ m_nBeatCounter
1106
1108{
1109#ifdef H2CORE_HAVE_JACK
1110 AudioEngine* pAudioEngine = m_pAudioEngine;
1111
1112 if ( hasJackTransport() ) {
1113 static_cast< JackAudioDriver* >( pAudioEngine->getAudioDriver() )->releaseTimebaseMaster();
1114 }
1115#endif
1116}
1117
1119{
1120#ifdef H2CORE_HAVE_JACK
1121 AudioEngine* pAudioEngine = m_pAudioEngine;
1122
1123 if ( hasJackTransport() ) {
1124 static_cast< JackAudioDriver* >( pAudioEngine->getAudioDriver() )->initTimebaseMaster();
1125 }
1126#endif
1127}
1128
1129void Hydrogen::addInstrumentToDeathRow( std::shared_ptr<Instrument> pInstr ) {
1130 __instrument_death_row.push_back( pInstr );
1132}
1133
1135{
1136 if ( __instrument_death_row.size() > 0 ) {
1137 std::shared_ptr<Instrument> pInstr = nullptr;
1138 while ( __instrument_death_row.size()
1139 && __instrument_death_row.front()->is_queued() == 0 ) {
1140 pInstr = __instrument_death_row.front();
1141 __instrument_death_row.pop_front();
1142 INFOLOG( QString( "Deleting unused instrument (%1). "
1143 "%2 unused remain." )
1144 . arg( pInstr->get_name() )
1145 . arg( __instrument_death_row.size() ) );
1146 pInstr = nullptr;
1147 }
1148 if ( __instrument_death_row.size() ) {
1149 pInstr = __instrument_death_row.front();
1150 INFOLOG( QString( "Instrument %1 still has %2 active notes. "
1151 "Delaying 'delete instrument' operation." )
1152 . arg( pInstr->get_name() )
1153 . arg( pInstr->is_queued() ) );
1154 }
1155 }
1156}
1157
1158
1159
1167
1169#ifdef H2CORE_HAVE_JACK
1170 if ( m_pAudioEngine->getAudioDriver() != nullptr ) {
1171 if ( dynamic_cast<JackAudioDriver*>(m_pAudioEngine->getAudioDriver()) != nullptr ) {
1172 return true;
1173 }
1174 }
1175 return false;
1176#else
1177 return false;
1178#endif
1179}
1180
1182#ifdef H2CORE_HAVE_JACK
1183 if ( m_pAudioEngine->getAudioDriver() != nullptr ) {
1184 if ( dynamic_cast<JackAudioDriver*>(m_pAudioEngine->getAudioDriver()) != nullptr &&
1187 return true;
1188 }
1189 }
1190 return false;
1191#else
1192 return false;
1193#endif
1194}
1195
1197#ifdef H2CORE_HAVE_JACK
1198 if ( m_pAudioEngine->getAudioDriver() != nullptr ) {
1199 if ( dynamic_cast<JackAudioDriver*>(m_pAudioEngine->getAudioDriver()) != nullptr ) {
1200 return static_cast<JackAudioDriver*>(m_pAudioEngine->getAudioDriver())->getMasterBpm();
1201 } else {
1202 return std::nan("No JACK driver");
1203 }
1204 } else {
1205 return std::nan("No audio driver");
1206 }
1207#else
1208 return std::nan("No JACK support");
1209#endif
1210}
1211
1213#ifdef H2CORE_HAVE_JACK
1214 AudioEngine* pAudioEngine = m_pAudioEngine;
1215 if ( hasJackTransport() ) {
1216 return static_cast<JackAudioDriver*>(pAudioEngine->getAudioDriver())->getTimebaseState();
1217 }
1219#else
1221#endif
1222}
1223
1225#ifdef H2CORE_HAVE_OSC
1226 if ( NsmClient::get_instance() != nullptr ) {
1227 if ( NsmClient::get_instance()->getUnderSessionManagement() ) {
1228 return true;
1229 } else {
1230 return false;
1231 }
1232 } else {
1233 return false;
1234 }
1235#else
1236 return false;
1237#endif
1238}
1239
1241 if ( __song->getIsTimelineActivated() &&
1244 return true;
1245 }
1246
1247 return false;
1248}
1249
1251 if ( getMode() == Song::Mode::Song &&
1252 __song != nullptr ) {
1253 if ( __song->getIsPatternEditorLocked() ) {
1254 return true;
1255 }
1256 }
1257
1258 return false;
1259}
1260
1262 if ( __song != nullptr &&
1263 bValue != __song->getIsPatternEditorLocked() ) {
1264 __song->setIsPatternEditorLocked( bValue );
1265 __song->setIsModified( true );
1266
1268
1270 bValue );
1271 }
1272}
1273
1275 if ( __song != nullptr ) {
1276 return __song->getMode();
1277 }
1278
1279 return Song::Mode::None;
1280}
1281
1283 if ( __song != nullptr && mode != __song->getMode() ) {
1284 __song->setMode( mode );
1286 ( mode == Song::Mode::Song) ? 1 : 0 );
1287 }
1288}
1289
1291 if ( __song != nullptr ) {
1292 return __song->getActionMode();
1293 }
1295}
1296
1298 if ( __song != nullptr ) {
1299 __song->setActionMode( mode );
1301 ( mode == Song::ActionMode::drawMode ) ? 1 : 0 );
1302 }
1303}
1304
1306 if ( getMode() == Song::Mode::Pattern ) {
1307 return __song->getPatternMode();
1308 }
1310}
1311
1313{
1314 if ( __song != nullptr &&
1315 getPatternMode() != mode ) {
1317
1318 __song->setPatternMode( mode );
1319 setIsModified( true );
1320
1322 mode == Song::PatternMode::Selected ) {
1323 // Only update the playing patterns in selected pattern
1324 // mode or if transport is not rolling. In stacked pattern
1325 // mode with transport rolling
1326 // AudioEngine::updatePatternTransportPosition() will call
1327 // the functions and activate the next patterns once the
1328 // current ones are looped.
1331 }
1332
1335 ( mode == Song::PatternMode::Selected ) ? 1 : 0 );
1336 }
1337}
1338
1340 if ( getMode() == Song::Mode::Song ) {
1342 return Tempo::Jack;
1343 } else if ( getSong()->getIsTimelineActivated() ) {
1344 return Tempo::Timeline;
1345 }
1346 }
1347
1348 return Tempo::Song;
1349}
1350
1351void Hydrogen::toggleOscServer( bool bEnable ) {
1352#ifdef H2CORE_HAVE_OSC
1353 if ( bEnable ) {
1355 } else {
1357 }
1358#endif
1359}
1360
1362#ifdef H2CORE_HAVE_OSC
1363 OscServer* pOscServer = OscServer::get_instance();
1364 if( pOscServer ) {
1365 delete pOscServer;
1366 }
1367
1369
1370 if ( Preferences::get_instance()->getOscServerEnabled() ) {
1371 toggleOscServer( true );
1372 }
1373#endif
1374}
1375
1377{
1378#ifdef H2CORE_HAVE_OSC
1379 //NSM has to be started before jack driver gets created
1380 NsmClient* pNsmClient = NsmClient::get_instance();
1381
1382 if(pNsmClient){
1383 pNsmClient->createInitialClient();
1384 }
1385#endif
1386}
1387
1388
1390
1391 if ( !Preferences::get_instance()->getRubberBandBatchMode() ) {
1392 return;
1393 }
1394
1395 if ( getSong() != nullptr ) {
1396 auto pInstrumentList = getSong()->getInstrumentList();
1397 if ( pInstrumentList != nullptr ) {
1398 for ( unsigned nnInstr = 0; nnInstr < pInstrumentList->size(); ++nnInstr ) {
1399 auto pInstr = pInstrumentList->get( nnInstr );
1400 if ( pInstr == nullptr ) {
1401 return;
1402 }
1403 assert( pInstr );
1404 if ( pInstr != nullptr ){
1405 for ( int nnComponent = 0; nnComponent < pInstr->get_components()->size();
1406 ++nnComponent ) {
1407 auto pInstrumentComponent = pInstr->get_component( nnComponent );
1408 if ( pInstrumentComponent == nullptr ) {
1409 continue; // regular case when you have a new component empty
1410 }
1411
1412 for ( int nnLayer = 0; nnLayer < InstrumentComponent::getMaxLayers(); nnLayer++ ) {
1413 auto pLayer = pInstrumentComponent->get_layer( nnLayer );
1414 if ( pLayer != nullptr ) {
1415 auto pSample = pLayer->get_sample();
1416 if ( pSample != nullptr ) {
1417 if( pSample->get_rubberband().use ) {
1418 auto pNewSample = std::make_shared<Sample>( pSample );
1419
1420 if ( ! pNewSample->load( fBpm ) ){
1421 continue;
1422 }
1423
1424 // insert new sample from newInstrument
1425 pLayer->set_sample( pNewSample );
1426 }
1427 }
1428 }
1429 }
1430 }
1431 }
1432 }
1433 setIsModified( true );
1434 } else {
1435 ERRORLOG( "No InstrumentList present" );
1436 }
1437 } else {
1438 ERRORLOG( "No song set" );
1439 }
1440}
1441
1442void Hydrogen::setIsModified( bool bIsModified ) {
1443 if ( getSong() != nullptr ) {
1444 if ( getSong()->getIsModified() != bIsModified ) {
1445 getSong()->setIsModified( bIsModified );
1446 }
1447 }
1448}
1450 if ( getSong() != nullptr ) {
1451 return getSong()->getIsModified();
1452 }
1453 return false;
1454}
1455
1457 if ( getSong() != nullptr ) {
1458 return getSong()->getLastLoadedDrumkitPath();
1459 }
1460 ERRORLOG( "no song set yet" );
1461
1462 return "";
1463}
1464
1466 if ( getSong() != nullptr ) {
1467 return getSong()->getLastLoadedDrumkitName();
1468 }
1469 ERRORLOG( "no song set yet" );
1470
1471 return "";
1472}
1473
1475 if ( getSong() != nullptr ) {
1476 auto pPref = Preferences::get_instance();
1477 auto pAudioEngine = getAudioEngine();
1478
1479 if ( bEnabled != getSong()->getIsTimelineActivated() ) {
1480
1481 pAudioEngine->lock( RIGHT_HERE );
1482
1483 // DEBUGLOG( QString( "bEnabled: %1, getSong()->getIsTimelineActivated(): %2" )
1484 // .arg( bEnabled )
1485 // .arg( getSong()->getIsTimelineActivated()) );
1486
1487 pPref->setUseTimelineBpm( bEnabled );
1488 getSong()->setIsTimelineActivated( bEnabled );
1489
1490 if ( bEnabled ) {
1491 getTimeline()->activate();
1492 } else {
1493 getTimeline()->deactivate();
1494 }
1495
1496 pAudioEngine->handleTimelineChange();
1497 pAudioEngine->unlock();
1498
1499 EventQueue::get_instance()->push_event( EVENT_TIMELINE_ACTIVATION, static_cast<int>( bEnabled ) );
1500 }
1501 }
1502}
1503
1504int Hydrogen::getColumnForTick( long nTick, bool bLoopMode, long* pPatternStartTick ) const
1505{
1506 std::shared_ptr<Song> pSong = getSong();
1507 assert( pSong );
1508
1509 long nTotalTick = 0;
1510
1511 std::vector<PatternList*> *pPatternColumns = pSong->getPatternGroupVector();
1512 int nColumns = pPatternColumns->size();
1513
1514 if ( nColumns == 0 ) {
1515 // There are no patterns in the current song.
1516 *pPatternStartTick = 0;
1517 return 0;
1518 }
1519
1520 // Sum the lengths of all pattern columns and use the macro
1521 // MAX_NOTES in case some of them are of size zero. If the
1522 // supplied value nTick is bigger than this and doesn't belong to
1523 // the next pattern column, we just found the pattern list we were
1524 // searching for.
1525 int nPatternSize;
1526 for ( int i = 0; i < nColumns; ++i ) {
1527 PatternList *pColumn = ( *pPatternColumns )[ i ];
1528 if ( pColumn->size() != 0 ) {
1529 nPatternSize = pColumn->longest_pattern_length();
1530 } else {
1531 nPatternSize = MAX_NOTES;
1532 }
1533
1534 if ( ( nTick >= nTotalTick ) && ( nTick < nTotalTick + nPatternSize ) ) {
1535 ( *pPatternStartTick ) = nTotalTick;
1536 return i;
1537 }
1538 nTotalTick += nPatternSize;
1539 }
1540
1541 // If the song is played in loop mode, the tick numbers of the
1542 // second turn are added on top of maximum tick number of the
1543 // song. Therefore, we will introduced periodic boundary
1544 // conditions and start the search again.
1545 if ( bLoopMode ) {
1546 long nLoopTick = 0;
1547 // nTotalTicks is now the same as m_nSongSizeInTicks
1548 if ( nTotalTick != 0 ) {
1549 nLoopTick = nTick % nTotalTick;
1550 }
1551 nTotalTick = 0;
1552 for ( int i = 0; i < nColumns; ++i ) {
1553 PatternList *pColumn = ( *pPatternColumns )[ i ];
1554 if ( pColumn->size() != 0 ) {
1555 nPatternSize = pColumn->longest_pattern_length();
1556 } else {
1557 nPatternSize = MAX_NOTES;
1558 }
1559
1560 if ( ( nLoopTick >= nTotalTick )
1561 && ( nLoopTick < nTotalTick + nPatternSize ) ) {
1562 ( *pPatternStartTick ) = nTotalTick;
1563 return i;
1564 }
1565 nTotalTick += nPatternSize;
1566 }
1567 }
1568
1569 ( *pPatternStartTick ) = 0;
1570 return -1;
1571}
1572
1573long Hydrogen::getTickForColumn( int nColumn ) const
1574{
1575 auto pSong = getSong();
1576 assert( pSong );
1577
1578 const int nPatternGroups = pSong->getPatternGroupVector()->size();
1579 if ( nPatternGroups == 0 ) {
1580 // No patterns in song.
1581 return 0;
1582 }
1583
1584 if ( nColumn >= nPatternGroups ) {
1585 // The position is beyond the end of the Song, we
1586 // set periodic boundary conditions or return the
1587 // beginning of the Song as a fallback.
1588 if ( pSong->isLoopEnabled() ) {
1589 nColumn = nColumn % nPatternGroups;
1590 } else {
1591 WARNINGLOG( QString( "Provided column [%1] is larger than the available number [%2]")
1592 .arg( nColumn ) .arg( nPatternGroups )
1593 );
1594 return -1;
1595 }
1596 }
1597
1598 std::vector<PatternList*> *pColumns = pSong->getPatternGroupVector();
1599 long totalTick = 0;
1600 int nPatternSize;
1601 Pattern *pPattern = nullptr;
1602
1603 for ( int i = 0; i < nColumn; ++i ) {
1604 PatternList *pColumn = ( *pColumns )[ i ];
1605
1606 if( pColumn->size() > 0)
1607 {
1608 nPatternSize = pColumn->longest_pattern_length();
1609 } else {
1610 nPatternSize = MAX_NOTES;
1611 }
1612 totalTick += nPatternSize;
1613 }
1614
1615 return totalTick;
1616}
1617
1621
1622std::shared_ptr<Instrument> Hydrogen::getSelectedInstrument() const {
1623
1624 std::shared_ptr<Instrument> pInstrument = nullptr;
1625
1626 if ( __song != nullptr ) {
1627
1629
1630 int nSelectedInstrumentNumber = m_nSelectedInstrumentNumber;
1631 auto pInstrList = __song->getInstrumentList();
1632 if ( nSelectedInstrumentNumber >= pInstrList->size() ) {
1633 nSelectedInstrumentNumber = -1;
1634 }
1635
1636 if ( nSelectedInstrumentNumber != -1 ) {
1637 pInstrument = pInstrList->get( nSelectedInstrumentNumber );
1638 }
1639
1641 }
1642
1643 return pInstrument;
1644}
1645
1647
1648 if ( __song == nullptr ) {
1649 ERRORLOG( "no song" );
1650 return;
1651 }
1652 PatternList *pPatternList = __song->getPatternList();
1653 if ( pPatternList == nullptr ) {
1654 ERRORLOG( "no pattern list");
1655 return;
1656 }
1657
1658 pPatternList->flattened_virtual_patterns_compute();
1659
1663
1665}
1666
1667QString Hydrogen::toQString( const QString& sPrefix, bool bShort ) const {
1668
1669 QString s = Base::sPrintIndention;
1670 QString sOutput;
1671 if ( ! bShort ) {
1672 sOutput = QString( "%1[Hydrogen]\n" ).arg( sPrefix )
1673 .append( QString( "%1%2__song: " ).arg( sPrefix ).arg( s ) );
1674 if ( __song != nullptr ) {
1675 sOutput.append( QString( "%1" ).arg( __song->toQString( sPrefix + s, bShort ) ) );
1676 } else {
1677 sOutput.append( QString( "nullptr\n" ) );
1678 }
1679 sOutput.append( QString( "%1%2m_ntaktoMeterCompute: %3\n" ).arg( sPrefix ).arg( s ).arg( m_ntaktoMeterCompute ) )
1680 .append( QString( "%1%2m_nbeatsToCount: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nbeatsToCount ) )
1681 .append( QString( "%1%2m_nEventCount: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nEventCount ) )
1682 .append( QString( "%1%2m_nTempoChangeCounter: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nTempoChangeCounter ) )
1683 .append( QString( "%1%2m_nBeatCount: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nBeatCount ) )
1684 .append( QString( "%1%2m_nBeatDiffs: [" ).arg( sPrefix ).arg( s ) );
1685 for ( auto dd : m_nBeatDiffs ) {
1686 sOutput.append( QString( " %1" ).arg( dd ) );
1687 }
1688 sOutput.append( QString( "]\n%1%2m_CurrentTime: %3" ).arg( sPrefix ).arg( s ).arg( static_cast<long>(m_CurrentTime.tv_sec ) ) )
1689 .append( QString( "%1%2m_nCoutOffset: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nCoutOffset ) )
1690 .append( QString( "%1%2m_nStartOffset: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nStartOffset ) )
1691 .append( QString( "%1%2m_oldEngineMode: %3\n" ).arg( sPrefix ).arg( s )
1692 .arg( static_cast<int>(m_oldEngineMode) ) )
1693 .append( QString( "%1%2m_bOldLoopEnabled: %3\n" ).arg( sPrefix ).arg( s ).arg( m_bOldLoopEnabled ) )
1694 .append( QString( "%1%2m_bExportSessionIsActive: %3\n" ).arg( sPrefix ).arg( s ).arg( m_bExportSessionIsActive ) )
1695 .append( QString( "%1%2m_GUIState: %3\n" ).arg( sPrefix ).arg( s ).arg( static_cast<int>( m_GUIState ) ) )
1696 .append( QString( "%1%2m_pTimeline:\n" ).arg( sPrefix ).arg( s ) );
1697 if ( m_pTimeline != nullptr ) {
1698 sOutput.append( QString( "%1" ).arg( m_pTimeline->toQString( sPrefix + s, bShort ) ) );
1699 } else {
1700 sOutput.append( QString( "nullptr\n" ) );
1701 }
1702 sOutput.append( QString( "%1%2__instrument_death_row:\n" ).arg( sPrefix ).arg( s ) );
1703 for ( auto const& ii : __instrument_death_row ) {
1704 if ( ii != nullptr ) {
1705 sOutput.append( QString( "%1" ).arg( ii->toQString( sPrefix + s + s, bShort ) ) );
1706 } else {
1707 sOutput.append( QString( "nullptr\n" ) );
1708 }
1709 }
1710 sOutput.append( QString( "%1%2m_nSelectedInstrumentNumber: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nSelectedInstrumentNumber ) )
1711 .append( QString( "%1%2m_pAudioEngine:\n" ).arg( sPrefix ).arg( s ) );
1712 if ( m_pAudioEngine != nullptr ) {
1713 sOutput.append( QString( "%1" )
1714 .arg( m_pAudioEngine->toQString( sPrefix + s + s, bShort ) ) );
1715 } else {
1716 sOutput.append( QString( "nullptr\n" ) );
1717 }
1718 sOutput.append( QString( "%1%2lastMidiEvent: %3\n" ).arg( sPrefix ).arg( s )
1720 .append( QString( "%1%2lastMidiEventParameter: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nLastMidiEventParameter ) )
1721 .append( QString( "%1%2m_nInstrumentLookupTable: [ %3 ... %4 ]\n" ).arg( sPrefix ).arg( s )
1723 } else {
1724
1725 sOutput = QString( "%1[Hydrogen]" ).arg( sPrefix )
1726 .append( QString( ", __song: " ) );
1727 if ( __song != nullptr ) {
1728 sOutput.append( QString( "%1" ).arg( __song->toQString( sPrefix + s, bShort ) ) );
1729 } else {
1730 sOutput.append( QString( "nullptr" ) );
1731 }
1732 sOutput.append( QString( ", m_ntaktoMeterCompute: %1" ).arg( m_ntaktoMeterCompute ) )
1733 .append( QString( ", m_nbeatsToCount: %1" ).arg( m_nbeatsToCount ) )
1734 .append( QString( ", m_nEventCount: %1" ).arg( m_nEventCount ) )
1735 .append( QString( ", m_nTempoChangeCounter: %1" ).arg( m_nTempoChangeCounter ) )
1736 .append( QString( ", m_nBeatCount: %1" ).arg( m_nBeatCount ) )
1737 .append( QString( ", m_nBeatDiffs: [" ) );
1738 for ( auto dd : m_nBeatDiffs ) {
1739 sOutput.append( QString( " %1" ).arg( dd ) );
1740 }
1741 sOutput.append( QString( "], m_CurrentTime: %1" ).arg( static_cast<long>( m_CurrentTime.tv_sec ) ) )
1742 .append( QString( ", m_nCoutOffset: %1" ).arg( m_nCoutOffset ) )
1743 .append( QString( ", m_nStartOffset: %1" ).arg( m_nStartOffset ) )
1744 .append( QString( ", m_oldEngineMode: %1" )
1745 .arg( static_cast<int>(m_oldEngineMode) ) )
1746 .append( QString( ", m_bOldLoopEnabled: %1" ).arg( m_bOldLoopEnabled ) )
1747 .append( QString( ", m_bExportSessionIsActive: %1" ).arg( m_bExportSessionIsActive ) )
1748 .append( QString( ", m_GUIState: %1" ).arg( static_cast<int>( m_GUIState ) ) );
1749 sOutput.append( QString( ", m_pTimeline: " ) );
1750 if ( m_pTimeline != nullptr ) {
1751 sOutput.append( QString( "%1" ).arg( m_pTimeline->toQString( sPrefix, bShort ) ) );
1752 } else {
1753 sOutput.append( QString( "nullptr" ) );
1754 }
1755 sOutput.append( QString( ", __instrument_death_row: [" ) );
1756 for ( auto const& ii : __instrument_death_row ) {
1757 if ( ii != nullptr ) {
1758 sOutput.append( QString( "%1" ).arg( ii->toQString( sPrefix + s + s, bShort ) ) );
1759 } else {
1760 sOutput.append( QString( " nullptr" ) );
1761 }
1762 }
1763 sOutput.append( QString( ", m_nSelectedInstrumentNumber: %1" ).arg( m_nSelectedInstrumentNumber ) )
1764 .append( ", m_pAudioEngine:" );
1765 if ( m_pAudioEngine != nullptr ) {
1766 sOutput.append( QString( "%1" )
1767 .arg( m_pAudioEngine->toQString( sPrefix, bShort ) ) );
1768 } else {
1769 sOutput.append( QString( " nullptr" ) );
1770 }
1771 sOutput.append( QString( ", lastMidiEvent: %1" )
1773 .append( QString( ", lastMidiEventParameter: %1" ).arg( m_nLastMidiEventParameter ) )
1774 .append( QString( ", m_nInstrumentLookupTable: [ %1 ... %2 ]" )
1776 }
1777
1778 return sOutput;
1779}
1780
1781}; /* Namespace */
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
Definition AudioEngine.h:59
#define INFOLOG(x)
Definition Object.h:237
#define WARNINGLOG(x)
Definition Object.h:238
#define ERRORLOG(x)
Definition Object.h:239
#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.
Definition Pattern.h:290
int gettimeofday(struct timeval *tv, struct timezone *tz)
The audio engine deals with two distinct #TransportPosition.
Definition AudioEngine.h:97
void flushAndAddNextPattern(int nPatternNumber)
Add pattern nPatternNumber to #m_pNextPatterns as well as the whole content of #m_pPlayingPatterns.
void handleSelectedPattern()
Keeps the selected pattern in line with the one the transport position resides in while in Song::Mode...
void setSong(std::shared_ptr< Song >pNewSong)
void toggleNextPattern(int nPatternNumber)
Add pattern nPatternNumber to #m_pNextPatterns or deletes it in case it is already present.
@ Initialized
Not ready, but most pointers are now valid or NULL.
@ Playing
Transport is rolling.
void setNextBpm(float fNextBpm)
Stores the new speed into a separate variable which will be adopted during the next processing cycle.
AudioOutput * createAudioDriver(const QString &sDriver)
Create an audio driver using audioEngine_process() as its argument based on the provided choice and c...
void play()
Marks the audio engine to be started during the next call of the audioEngine_process() callback funct...
void updatePlayingPatterns()
Update the list of currently played patterns associated with m_pTransportPosition and m_pQueuingPosit...
void stop()
Marks the audio engine to be stopped during the next call of the audioEngine_process() callback funct...
void unlock()
Mutex unlocking of the AudioEngine.
void lock(const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
State getState() const
AudioOutput * getAudioDriver() const
void updateSongSize()
Function to be called every time the length of the current song does change, e.g.
Sampler * getSampler() const
void stopAudioDrivers()
Stops all audio and MIDI drivers.
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
const std::shared_ptr< TransportPosition > getTransportPosition() const
void noteOn(Note *note)
MidiOutput * getMidiOutDriver() const
void raiseError(unsigned nErrorCode)
MidiInput * getMidiDriver() const
Base abstract class for audio output classes.
Definition AudioOutput.h:39
virtual unsigned getSampleRate()=0
static QString sPrintIndention
String used to format the debugging string output of some core classes.
Definition Object.h:127
bool locateToTick(long nTick, bool bWithJackBroadcast=true)
Relocates transport to a particular tick.
Driver for export audio to disk.
void setSampleRate(unsigned nNewRate)
void setSampleDepth(int nNewDepth)
void setFileName(const QString &sFilename)
static EventQueue * get_instance()
Returns a pointer to the current EventQueue singleton stored in __instance.
Definition EventQueue.h:224
void push_event(const EventType type, const int nValue)
Queues the next event into the EventQueue.
static void create_instance()
If __instance equals 0, a new EventQueue singleton will be created and stored in it.
std::vector< AddMidiNoteVector > m_addMidiNoteVector
Definition EventQueue.h:274
Basic building block for the communication between the core of Hydrogen and its GUI.
Definition EventQueue.h:186
static bool file_exists(const QString &path, bool silent=false)
returns true if the given path is an existing regular file
bool isTimelineEnabled() const
Convenience function checking whether using the Timeline tempo is set in the Preferences,...
GUIState m_GUIState
Specifies whether the Qt5 GUI is active.
Definition Hydrogen.h:539
void setMode(Song::Mode mode)
Wrapper around Song::setMode() which also triggers EVENT_SONG_MODE_ACTIVATION and should be used by a...
bool m_bExportSessionIsActive
Definition Hydrogen.h:528
void initBeatcounter()
Auxiliary function setting a bunch of global variables.
Definition Hydrogen.cpp:206
JackAudioDriver::Timebase getJackTimebaseState() const
std::shared_ptr< Timeline > m_pTimeline
Local instance of the Timeline object.
Definition Hydrogen.h:544
void midi_noteOn(Note *note)
Definition Hydrogen.cpp:352
bool startExportSession(int rate, int depth)
Definition Hydrogen.cpp:631
float getMasterBpm() const
void addRealtimeNote(int instrument, float velocity, float fPan=0.0f, bool noteoff=false, int msg1=0)
Definition Hydrogen.cpp:357
int m_nSelectedPatternNumber
Index of the pattern selected in the GUI or by a MIDI event.
Definition Hydrogen.h:565
Hydrogen()
Constructor, entry point, and initialization of the Hydrogen application.
Definition Hydrogen.cpp:105
long getTickForColumn(int nColumn) const
Get the total number of ticks passed up to a nColumn / pattern group.
int m_nStartOffset
ms default 0
Definition Hydrogen.h:521
void restartDrivers()
Definition Hydrogen.cpp:626
void onJackMaster()
Calling JackAudioDriver::initTimebaseMaster() directly from the GUI.
Tempo
Specifies where the #AudioEngine does get its current tempo updates from.
Definition Hydrogen.h:60
@ Timeline
Only tempo markers on the Timeline are considered.
@ Jack
Hydrogen will disregard all internal tempo settings and uses the ones provided by the JACK server ins...
@ Song
BeatCounter, TapTempo, OSC and MIDI commands as well as the BPM widget in the PlayerControl are used ...
bool hasJackAudioDriver() const
void sequencer_stop()
Stop the internal sequencer.
Definition Hydrogen.cpp:226
void recreateOscServer()
Destroys and recreates the OscServer singleton in order to adopt a new OSC port.
void renameJackPorts(std::shared_ptr< Song > pSong)
Calls audioEngine_renameJackPorts() if Preferences::m_bJackTrackOuts is set to true.
Definition Hydrogen.cpp:931
~Hydrogen()
Destructor taking care of most of the clean up.
Definition Hydrogen.cpp:154
std::shared_ptr< Song > getSong() const
Get the current song.
Definition Hydrogen.h:122
int m_nSelectedInstrumentNumber
Instrument currently focused/selected in the GUI.
Definition Hydrogen.h:561
void toggleNextPattern(int nPatternNumber)
Wrapper around AudioEngine::toggleNextPattern().
Definition Hydrogen.cpp:598
QString getLastLoadedDrumkitPath() const
std::list< std::shared_ptr< Instrument > > __instrument_death_row
Deleting instruments too soon leads to potential crashes.
Definition Hydrogen.h:551
void removeInstrument(int nInstrumentNumber)
Delete an #Instrument.
Definition Hydrogen.cpp:754
void setBcOffsetAdjust()
Definition Hydrogen.cpp:983
void setIsTimelineActivated(bool bEnabled)
Wrapper around both Song::setIsTimelineActivated (recent) and Preferences::setUseTimelinebpm() (forme...
int m_nInstrumentLookupTable[MAX_INSTRUMENTS]
midi lookuptable
Definition Hydrogen.h:450
void stopExportSession()
Definition Hydrogen.cpp:699
int getSelectedInstrumentNumber() const
Definition Hydrogen.h:664
void setPatternMode(Song::PatternMode mode)
Wrapper around Song::setPatternMode() which also triggers EVENT_STACKED_MODE_ACTIVATION and should be...
void onTapTempoAccelEvent()
Definition Hydrogen.cpp:779
Song::ActionMode getActionMode() const
bool isUnderSessionManagement() const
void setSong(std::shared_ptr< Song > newSong, bool bRelinking=true)
Sets the current song __song to newSong.
Definition Hydrogen.cpp:288
MidiInput * getMidiInput() const
Used to display midi driver info.
Definition Hydrogen.cpp:725
bool flushAndAddNextPattern(int nPatternNumber)
Wrapper around AudioEngine::flushAndAddNextPattern().
Definition Hydrogen.cpp:610
void setbeatsToCount(int beatstocount)
Updates m_nbeatsToCount.
Definition Hydrogen.cpp:958
GUIState
Specifies the state of the Qt GUI.
Definition Hydrogen.h:388
@ ready
There is a working GUI.
Song::PlaybackTrack getPlaybackTrackState() const
Wrapper around Song::getPlaybackTrackState().
Definition Hydrogen.cpp:240
int m_nLastRecordedMIDINoteTick
Onset of the recorded last in addRealtimeNote().
Definition Hydrogen.h:594
float m_ntaktoMeterCompute
beatcounter note length
Definition Hydrogen.h:513
std::shared_ptr< Song > __song
Pointer to the current song.
Definition Hydrogen.h:497
void setTapTempo(float fInterval)
Definition Hydrogen.cpp:804
Tempo getTempoSource() const
int getColumnForTick(long nTick, bool bLoopMode, long *pPatternStartTick) const
Find a PatternList/column corresponding to the supplied tick position nTick.
double m_nBeatDiffs[16]
beat diff
Definition Hydrogen.h:518
Song::Mode getMode() const
static void create_instance()
Creates all the instances used within Hydrogen in the right order.
Definition Hydrogen.cpp:181
void updateVirtualPatterns()
Processes the patterns added to any virtual ones in the #PatternList of the current Song and ensure b...
void setSelectedInstrumentNumber(int nInstrument, bool bTriggerEvent=true)
Definition Hydrogen.cpp:918
void restartLadspaFX()
Definition Hydrogen.cpp:864
std::shared_ptr< Timeline > getTimeline() const
Definition Hydrogen.h:630
SoundLibraryDatabase * m_pSoundLibraryDatabase
Definition Hydrogen.h:600
void offJackMaster()
Calling JackAudioDriver::releaseTimebaseMaster() directly from the GUI.
void mutePlaybackTrack(const bool bMuted)
Wrapper around Song::setPlaybackTrackEnabled().
Definition Hydrogen.cpp:250
AudioEngine * m_pAudioEngine
Central instance of the audio engine.
Definition Hydrogen.h:598
MidiMessage::Event m_lastMidiEvent
Cache last incoming MIDI event to be used in MidiSenseWidget.
Definition Hydrogen.h:621
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:83
Song::PatternMode getPatternMode() const
static Hydrogen * __instance
Static reference to the Hydrogen singleton.
Definition Hydrogen.h:490
void __kill_instruments()
void updateSelectedPattern(bool bNeedsLock=true)
Updates the selected pattern to the one recorded note will be inserted to.
Definition Hydrogen.cpp:877
void setIsPatternEditorLocked(bool bValue)
MidiOutput * getMidiOutput() const
Definition Hydrogen.cpp:730
void startExportSong(const QString &filename)
Export a song to a wav file.
Definition Hydrogen.cpp:680
int m_nTempoChangeCounter
count tempochanges for timeArray
Definition Hydrogen.h:516
int m_nbeatsToCount
beatcounter beats to count
Definition Hydrogen.h:514
bool handleBeatCounter()
Definition Hydrogen.cpp:993
int m_nEventCount
beatcounter event
Definition Hydrogen.h:515
AudioEngine * getAudioEngine() const
Definition Hydrogen.h:649
void setNoteLength(float notelength)
Definition Hydrogen.cpp:968
std::shared_ptr< Instrument > getSelectedInstrument() const
int m_nLastMidiEventParameter
Definition Hydrogen.h:622
void loadPlaybackTrack(QString sFilename)
Wrapper function for loading the playback track.
Definition Hydrogen.cpp:262
AudioOutput * getAudioOutput() const
Used to display audio driver info.
Definition Hydrogen.cpp:719
bool m_bOldLoopEnabled
Definition Hydrogen.h:527
void setIsModified(bool bIsModified)
Wrapper around Song::setIsModified() that checks whether a song is set.
void addInstrumentToDeathRow(std::shared_ptr< Instrument > pInstr)
Add pInstr to __instrument_death_row and triggers __kill_instruments().
bool instrumentHasNotes(std::shared_ptr< Instrument > pInst)
Test if an Instrument has some Note in the Pattern (used to test before deleting an Instrument)
Definition Hydrogen.cpp:736
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
void setSessionDrumkitNeedsRelinking(bool bNeedsRelinking)
Definition Hydrogen.h:669
bool isPatternEditorLocked() const
Convenience function checking whether using the Pattern Editor is locked in the song settings and the...
void stopExportSong()
Definition Hydrogen.cpp:692
void setActionMode(Song::ActionMode mode)
Wrapper around Song::setActionMode() which also triggers EVENT_ACTION_MODE_CHANGE and should be used ...
void setSelectedPatternNumber(int nPat, bool bNeedsLock=true, bool bForce=false)
Sets m_nSelectedPatternNumber.
Definition Hydrogen.cpp:889
bool hasJackTransport() const
float getNoteLength()
Definition Hydrogen.cpp:973
void toggleOscServer(bool bEnable)
Starts/stops the OSC server.
bool getIsModified() const
Wrapper around Song::getIsModified() that checks whether a song is set.
timeval m_CurrentTime
timeval
Definition Hydrogen.h:519
QString getLastLoadedDrumkitName() const
CoreActionController * getCoreActionController() const
Definition Hydrogen.h:639
Song::Mode m_oldEngineMode
ms default 0
Definition Hydrogen.h:526
CoreActionController * m_pCoreActionController
Local instance of the CoreActionController object.
Definition Hydrogen.h:548
void raiseError(unsigned nErrorCode)
Definition Hydrogen.cpp:774
int m_nBeatCount
beatcounter beat to count
Definition Hydrogen.h:517
void sequencer_play()
Start the internal sequencer.
Definition Hydrogen.cpp:218
GUIState getGUIState() const
Definition Hydrogen.h:653
void recalculateRubberband(float fBpm)
Recalculates all Samples using RubberBand for a specific tempo fBpm.
static void setMaxLayers(int layers)
JACK (Jack Audio Connection Kit) server driver.
Timebase
Whether Hydrogen or another program is Jack timebase master.
@ None
Only normal clients registered.
@ Slave
An external program is timebase master and Hydrogen will disregard all tempo markers on the Timeline ...
static Logger * create_instance(const QString &sLogFilePath=QString(), bool bUseStdout=true)
If __instance equals 0, a new H2Core::Logger singleton will be created and stored in it.
Definition Logger.cpp:107
MIDI input base class.
Definition MidiInput.h:39
static QString EventToQString(Event event)
MIDI input base class.
Definition MidiOutput.h:41
virtual void handleQueueAllNoteOff()=0
A note plays an associated instrument with a velocity left and right pan.
Definition Note.h:102
int get_position() const
__position accessor
Definition Note.h:535
void set_length(int value)
__length setter
Definition Note.h:555
std::shared_ptr< Instrument > get_instrument()
__instrument accessor
Definition Note.h:500
Key
possible keys
Definition Note.h:106
static double pitchToFrequency(double fPitch)
Convert a logarithmic pitch-space value in semitones to a frequency-domain value.
Definition Note.h:388
void set_note_off(bool value)
__note_off setter
Definition Note.h:575
void set_midi_info(Key key, Octave octave, int msg)
set __key, __octave and __midi_msg only if within acceptable range
Definition Note.h:706
Octave
possible octaves
Definition Note.h:110
PatternList is a collection of patterns.
Definition PatternList.h:43
int index(const Pattern *pattern) const
get the index of the pattern within the patterns
void flattened_virtual_patterns_compute()
call compute_flattened_virtual_patterns on each pattern
int longest_pattern_length(bool bIncludeVirtuals=true) const
Get the length of the longest pattern in the list.
int size() const
returns the numbers of patterns
Pattern * get(int idx)
get a pattern from the list
Pattern class is a Note container.
Definition Pattern.h:46
const QString & get_name() const
set the category of the pattern
Definition Pattern.h:310
bool references(std::shared_ptr< Instrument > instr)
check if this pattern contains a note referencing the given instrument
Definition Pattern.cpp:255
int get_length() const
set the denominator of the pattern
Definition Pattern.h:340
const notes_t * get_notes() const
get the virtual pattern set
Definition Pattern.h:355
std::multimap< int, Note * > notes_t
< multimap note type
Definition Pattern.h:50
static void create_instance()
If __instance equals 0, a new Playlist singleton will be created and stored in it.
Definition Playlist.cpp:50
Manager for User Preferences File (singleton)
Definition Preferences.h:78
bool inPunchArea(int pos)
static Preferences * get_instance()
Returns a pointer to the current Preferences singleton stored in __instance.
int getPatternEditorGridResolution()
bool isPatternEditorUsingTriplets()
static void create_instance()
If __instance equals 0, a new Preferences singleton will be created and stored in it.
@ USE_JACK_TRANSPORT
Specifies whether or not to use JACK transport capabilities.
Definition Preferences.h:89
int m_bJackTransportMode
Specifies whether or not Hydrogen will use the JACK transport system.
void setRecordEvents(bool value)
void reinitializePlaybackTrack()
Loading of the playback track.
Definition Sampler.cpp:1436
void stopPlayingNotes(std::shared_ptr< Instrument > pInstr=nullptr)
Definition Sampler.cpp:1341
@ None
Used in case no song is set and both pattern and song editor are not ready to operate yet.
ActionMode
Defines the type of user interaction experienced in the SongEditor.
Definition Song.h:74
@ drawMode
Holding a pressed left mouse key will draw/delete patterns in all grid cells encountered.
@ None
Used in case no song is set and both pattern and song editor are not ready to operate yet.
PlaybackTrack
Determines the state of the Playback track with respect to audio processing.
Definition Song.h:115
@ None
Null element used to indicate that either no song is present.
PatternMode
Determines how patterns will be added to AudioEngine::m_pPlayingPatterns if transport is in Song::Mod...
Definition Song.h:101
@ None
Null element used to indicate that either no song is present or Song::Mode::Song was selected.
@ Selected
Only one pattern - the one currently selected in the GUI - will be played back.
static void create_instance()
If __instance equals 0, a new MidiActionManager singleton will be created and stored in it.
static void create_instance()
If __instance equals 0, a new MidiMap singleton will be created and stored in it.
Definition MidiMap.cpp:64
Non session manager client implementation.
Definition NsmClient.h:58
static NsmClient * get_instance()
Definition NsmClient.h:84
static void create_instance()
If __instance equals nullptr, a new NsmClient singleton will be created and stored in it.
Definition NsmClient.cpp:63
void shutdown()
Causes the NSM client to not process events anymore.
void createInitialClient()
Actual setup, initialization, and registration of the NSM client.
OSC Server implementation.
Definition OscServer.h:90
static OscServer * get_instance()
Returns a pointer to the current OscServer singleton stored in __instance.
Definition OscServer.h:123
bool stop()
Stops the OSC server and makes it unavailable.
bool start()
Starts the OSC server and makes it available to handle commands.
static void create_instance(H2Core::Preferences *pPreferences)
If __instance equals nullptr, a new OscServer singleton will be created by calling the OscServer() co...
#define MAX_INSTRUMENTS
Maximum number of instruments allowed in Hydrogen.
Definition config.dox:70
#define MAX_NOTES
Maximum number of notes.
Definition config.dox:79
#define MIN_BPM
Definition Globals.h:35
#define US_DIVIDER
Definition Globals.h:46
@ EVENT_PLAYBACK_TRACK_CHANGED
Definition EventQueue.h:175
@ EVENT_STATE
Definition EventQueue.h:43
@ 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_NEXT_PATTERNS_CHANGED
Used in Song::PatternMode::Stacked to indicate that a either AudioEngine::getNextPatterns() did chang...
Definition EventQueue.h:64
@ EVENT_PATTERN_EDITOR_LOCKED
Locks the PatternEditor on the pattern currently played back.
Definition EventQueue.h:160
@ 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_STACKED_MODE_ACTIVATION
Song::PatternMode::Stacked (0) or Song::PatternMode::Selected (1) was activated.
Definition EventQueue.h:148