hydrogen 1.2.6
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-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#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
104
107 , m_bExportSessionIsActive( false )
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 , m_nHihatOpenness( 127 )
118{
119 if ( __instance ) {
120 ERRORLOG( "Hydrogen audio engine is already running" );
121 throw H2Exception( "Hydrogen audio engine is already running" );
122 }
123
124 INFOLOG( "[Hydrogen]" );
125
126 __song = nullptr;
127
128 m_pTimeline = std::make_shared<Timeline>();
129 m_pCoreActionController = new CoreActionController();
130
131 initBeatcounter();
133
134 m_pAudioEngine = new AudioEngine();
136
138
139 // Prevent double creation caused by calls from MIDI thread
140 __instance = this;
141
142 m_pAudioEngine->startAudioDrivers();
143
144 for(int i = 0; i< MAX_INSTRUMENTS; i++){
145 m_nInstrumentLookupTable[i] = i;
146 }
147
148 if ( Preferences::get_instance()->getOscServerEnabled() ) {
149 toggleOscServer( true );
150 }
151
152 m_pSoundLibraryDatabase = new SoundLibraryDatabase();
153}
154
156{
157 INFOLOG( "[~Hydrogen]" );
158
159#ifdef H2CORE_HAVE_OSC
160 NsmClient* pNsmClient = NsmClient::get_instance();
161 if( pNsmClient ) {
162 pNsmClient->shutdown();
163 delete pNsmClient;
164 }
165 OscServer* pOscServer = OscServer::get_instance();
166 if( pOscServer ) {
167 delete pOscServer;
168 }
169#endif
170
171 m_pAudioEngine->lock( RIGHT_HERE );
172 removeSong();
173 m_pAudioEngine->unlock();
174
176
179 delete m_pAudioEngine;
180
181 __instance = nullptr;
182}
183
185{
186 // Create all the other instances that we need
187 // ....and in the right order
193
194#ifdef H2CORE_HAVE_OSC
197#endif
198
199 if ( __instance == nullptr ) {
200 __instance = new Hydrogen;
201 }
202
203 // See audioEngine_init() for:
204 // AudioEngine::create_instance();
205 // Effects::create_instance();
206 // Playlist::create_instance();
207}
208
219
222{
223 std::shared_ptr<Song> pSong = getSong();
224 if ( pSong != nullptr ) {
225 pSong->getPatternList()->set_to_old();
226 }
227 m_pAudioEngine->play();
228}
229
232{
233 if( Hydrogen::get_instance()->getMidiOutput() != nullptr ){
235 }
236
237 m_pAudioEngine->stop();
239
240 // Delete redundant instruments still alive after switching the
241 // drumkit to a smaller one.
243}
244
246
247 if ( __song == nullptr ) {
248 ERRORLOG( "No song set yet" );
250 }
251
252 return __song->getPlaybackTrackState();
253}
254
255void Hydrogen::mutePlaybackTrack( const bool bMuted )
256{
257 if ( __song == nullptr ) {
258 ERRORLOG( "No song set yet" );
259 return;
260 }
261
262 __song->setPlaybackTrackEnabled( bMuted );
263
265}
266
267void Hydrogen::loadPlaybackTrack( QString sFilename )
268{
269 if ( __song == nullptr ) {
270 ERRORLOG( "No song set yet" );
271 return;
272 }
273
274 if ( ! sFilename.isEmpty() &&
275 ! Filesystem::file_exists( sFilename, true ) ) {
276 ERRORLOG( QString( "Invalid playback track filename [%1]. File does not exist." )
277 .arg( sFilename ) );
278 sFilename = "";
279 }
280
281 if ( sFilename.isEmpty() ) {
282 INFOLOG( "Disable playback track" );
283 __song->setPlaybackTrackEnabled( false );
284 }
285
286 __song->setPlaybackTrackFilename( sFilename );
287
288 m_pAudioEngine->getSampler()->reinitializePlaybackTrack();
289
291}
292
293void Hydrogen::setSong( std::shared_ptr<Song> pSong, bool bRelinking )
294{
295 if ( pSong == nullptr ) {
296 WARNINGLOG( "setting nullptr!" );
297 }
298
299 std::shared_ptr<Song> pCurrentSong = getSong();
300 if ( pSong == pCurrentSong ) {
301 return;
302 }
303
304 m_pAudioEngine->lock( RIGHT_HERE );
305
306 // Move to the beginning.
307 setSelectedPatternNumber( 0, false );
308
309 if ( pCurrentSong != nullptr ) {
310 /* NOTE:
311 * - this is actually some kind of cleanup
312 * - removeSong cares itself for acquiring a lock
313 */
314
315 if ( isUnderSessionManagement() ) {
316 // When under session management Hydrogen is only allowed
317 // to replace the content of the session song but not to
318 // write to a different location.
319 if ( pSong != nullptr ) {
320 pSong->setFilename( pCurrentSong->getFilename() );
321 }
322 }
323 removeSong();
324 }
325
326 // In order to allow functions like audioEngine_setupLadspaFX() to
327 // load the settings of the new song, like whether the LADSPA FX
328 // are activated, __song has to be set prior to the call of
329 // audioEngine_setSong().
330 __song = pSong;
331
332 // Ensure the selected instrument is within the range of new
333 // instrument list.
334 if ( pSong != nullptr &&
335 m_nSelectedInstrumentNumber >= __song->getInstrumentList()->size() ) {
337 std::max( __song->getInstrumentList()->size() - 1, 0 );
338 }
339
340 // Update the audio engine to work with the new song.
341 m_pAudioEngine->setSong( pSong );
342
343 // load new playback track information
344 m_pAudioEngine->getSampler()->reinitializePlaybackTrack();
345
346 m_pAudioEngine->unlock();
347
348 // Push current state of Hydrogen to attached control interfaces,
349 // like OSC clients.
350 m_pCoreActionController->initExternalControlInterfaces();
351
352#ifdef H2CORE_HAVE_OSC
353 if ( isUnderSessionManagement() && bRelinking ) {
355 }
356#endif
357}
358
359/* Mean: remove current song from memory */
361{
362 m_pAudioEngine->removeSong();
363 __song = nullptr;
364}
365
367{
368 m_pAudioEngine->noteOn( note );
369}
370
371bool Hydrogen::addRealtimeNote( int nInstrument,
372 float fVelocity,
373 bool bNoteOff,
374 int nNote )
375{
376
377 AudioEngine* pAudioEngine = m_pAudioEngine;
378 auto pSampler = pAudioEngine->getSampler();
380 unsigned int nRealColumn = 0;
381 unsigned res = pPref->getPatternEditorGridResolution();
382 int nBase = pPref->isPatternEditorUsingTriplets() ? 3 : 4;
383 bool bPlaySelectedInstrument = pPref->__playselectedinstrument;
384 int scalar = ( 4 * MAX_NOTES ) / ( res * nBase );
385 int currentPatternNumber;
386
387 std::shared_ptr<Song> pSong = getSong();
388
389 if ( pSong == nullptr ) {
390 ERRORLOG( "No song set yet" );
391 return false;
392 }
393
394 m_pAudioEngine->lock( RIGHT_HERE );
395
396 if ( ! bPlaySelectedInstrument ) {
397 if ( nInstrument >= ( int ) pSong->getInstrumentList()->size() ) {
398 // unused instrument
399 ERRORLOG( QString( "Provided instrument [%1] not found" )
400 .arg( nInstrument ) );
401 pAudioEngine->unlock();
402 return false;
403 }
404 }
405
406 // Get current pattern and column
407 const Pattern* pCurrentPattern = nullptr;
408 long nTickInPattern = 0;
409 const float fPan = 0;
410
411 bool doRecord = pPref->getRecordEvents();
412 if ( getMode() == Song::Mode::Song && doRecord &&
413 pAudioEngine->getState() == AudioEngine::State::Playing ) {
414
415 // Recording + song playback mode + actually playing
416 PatternList* pPatternList = pSong->getPatternList();
417 auto pColumns = pSong->getPatternGroupVector();
418 int nColumn = pAudioEngine->getTransportPosition()->getColumn(); // current column
419 // or pattern group
420 if ( nColumn < 0 || nColumn >= pColumns->size() ) {
421 pAudioEngine->unlock(); // unlock the audio engine
422 ERRORLOG( QString( "Provided column [%1] out of bound [%2,%3)" )
423 .arg( nColumn ).arg( 0 )
424 .arg( pColumns->size() ) );
425 return false;
426 }
427 // Locate nTickInPattern -- may need to jump back one column
428 nTickInPattern = pAudioEngine->getTransportPosition()->getPatternTickPosition();
429
430 // Capture new notes in the bottom-most pattern (if not already done above)
431 PatternList *pColumn = ( *pColumns )[ nColumn ];
432 currentPatternNumber = -1;
433 for ( int n = 0; n < pColumn->size(); n++ ) {
434 Pattern *pPattern = pColumn->get( n );
435 int nIndex = pPatternList->index( pPattern );
436 if ( nIndex > currentPatternNumber ) {
437 currentPatternNumber = nIndex;
438 pCurrentPattern = pPattern;
439 }
440 }
441
442 // Cancel recording if punch area disagrees
443 doRecord = pPref->inPunchArea( nColumn );
444
445 }
446 else { // Not song-record mode
447 PatternList *pPatternList = pSong->getPatternList();
448
449 if ( ( m_nSelectedPatternNumber != -1 )
450 && ( m_nSelectedPatternNumber < ( int )pPatternList->size() ) )
451 {
452 pCurrentPattern = pPatternList->get( m_nSelectedPatternNumber );
453 currentPatternNumber = m_nSelectedPatternNumber;
454 }
455
456 if ( ! pCurrentPattern ) {
457 ERRORLOG( "Current pattern invalid" );
458 pAudioEngine->unlock(); // unlock the audio engine
459 return false;
460 }
461
462 // Locate nTickInPattern -- may need to wrap around end of pattern
463 nTickInPattern = pAudioEngine->getTransportPosition()->getPatternTickPosition();
464 }
465
466 if ( pCurrentPattern && pPref->getQuantizeEvents() ) {
467 // quantize it to scale
468 unsigned qcolumn = ( unsigned )::round( nTickInPattern / ( double )scalar ) * scalar;
469
470 //we have to make sure that no beat is added on the last displayed note in a bar
471 //for example: if the pattern has 4 beats, the editor displays 5 beats, so we should avoid adding beats an note 5.
472 if ( qcolumn == pCurrentPattern->get_length() ){
473 qcolumn = 0;
474 }
475 nTickInPattern = qcolumn;
476 }
477
478 auto pInstrumentList = pSong->getInstrumentList();
479 int nInstrumentNumber;
480 if ( bPlaySelectedInstrument ) {
481 nInstrumentNumber = getSelectedInstrumentNumber();
482 } else {
483 nInstrumentNumber = m_nInstrumentLookupTable[ nInstrument ];
484 }
485 auto pInstr = pInstrumentList->get( nInstrumentNumber );
486 if ( pInstr == nullptr ) {
487 ERRORLOG( QString( "Unable to retrieved instrument [%1]. Plays selected instrument: [%2]" )
488 .arg( nInstrumentNumber )
489 .arg( bPlaySelectedInstrument ) );
490 pAudioEngine->unlock();
491 return false;
492 }
493
494 // Record note
495 if ( pCurrentPattern != nullptr &&
496 pAudioEngine->getState() == AudioEngine::State::Playing &&
497 doRecord ) {
498
499 INFOLOG( QString( "Recording [%1] to pattern: %2 (%3), tick: [%4/%5]." )
500 .arg( bNoteOff ? "NoteOff" : "NoteOn")
501 .arg( currentPatternNumber ).arg( pCurrentPattern->get_name() )
502 .arg( nTickInPattern ).arg( pCurrentPattern->get_length() ) );
503
504 bool bIsModified = false;
505
506 if ( bNoteOff ) {
507
508 int nPatternSize = pCurrentPattern->get_length();
509 int nNoteLength =
510 static_cast<int>(pAudioEngine->getTransportPosition()->getPatternTickPosition()) -
512
513 if ( bPlaySelectedInstrument ) {
514 nNoteLength =
515 static_cast<int>(static_cast<double>(nNoteLength) *
516 Note::pitchToFrequency( nNote ));
517 }
518
519 for ( unsigned nNote = 0; nNote < nPatternSize; nNote++ ) {
520 const Pattern::notes_t* notes = pCurrentPattern->get_notes();
521 FOREACH_NOTE_CST_IT_BOUND_LENGTH( notes, it, nNote, pCurrentPattern ) {
522 Note *pNote = it->second;
523 if ( pNote != nullptr &&
525 pInstr == pNote->get_instrument() ) {
526
527 if ( m_nLastRecordedMIDINoteTick + nNoteLength > nPatternSize ) {
528 nNoteLength = nPatternSize - m_nLastRecordedMIDINoteTick;
529 }
530 pNote->set_length( nNoteLength );
531 bIsModified = true;
532 }
533 }
534 }
535
536 }
537 else { // note on
539 noteAction.m_column = nTickInPattern;
540 noteAction.m_row = nInstrumentNumber;
541 noteAction.m_pattern = currentPatternNumber;
542 noteAction.f_velocity = fVelocity;
543 noteAction.f_pan = fPan;
544 noteAction.m_length = -1;
545 noteAction.b_isMidi = true;
546
547 if ( bPlaySelectedInstrument ) {
548 int divider = nNote / 12;
549 noteAction.no_octaveKeyVal = (Note::Octave)(divider -3);
550 noteAction.nk_noteKeyVal = (Note::Key)(nNote - (12 * divider));
551 noteAction.b_isInstrumentMode = true;
552 } else {
553 noteAction.no_octaveKeyVal = (Note::Octave)0;
554 noteAction.nk_noteKeyVal = (Note::Key)0;
555 noteAction.b_isInstrumentMode = false;
556 }
557
558 EventQueue::get_instance()->m_addMidiNoteVector.push_back(noteAction);
559
560 m_nLastRecordedMIDINoteTick = nTickInPattern;
561
562 bIsModified = true;
563 }
564
565 if ( bIsModified ) {
567 setIsModified( true );
568 }
569 }
570
571 // Play back the note.
572 if ( ! pInstr->hasSamples() ) {
573 pAudioEngine->unlock();
574 return true;
575 }
576
577 if ( bPlaySelectedInstrument ) {
578 if ( bNoteOff ) {
579 if ( pSampler->isInstrumentPlaying( pInstr ) ) {
580 pSampler->midiKeyboardNoteOff( nNote );
581 }
582 }
583 else { // note on
584 Note *pNote2 = new Note( pInstr, nRealColumn, fVelocity, fPan );
585
586 int divider = nNote / 12;
587 Note::Octave octave = (Note::Octave)(divider -3);
588 Note::Key notehigh = (Note::Key)(nNote - (12 * divider));
589
590 pNote2->set_midi_info( notehigh, octave, nNote );
591 midi_noteOn( pNote2 );
592 }
593 }
594 else {
595 if ( bNoteOff ) {
596 if ( pSampler->isInstrumentPlaying( pInstr ) ) {
597 Note *pNoteOff = new Note( pInstr );
598 pNoteOff->set_note_off( true );
599 midi_noteOn( pNoteOff );
600 }
601 }
602 else { // note on
603 Note *pNote2 = new Note( pInstr, nRealColumn, fVelocity, fPan );
604 midi_noteOn( pNote2 );
605 }
606 }
607
608 m_pAudioEngine->unlock(); // unlock the audio engine
609 return true;
610}
611
612
613void Hydrogen::toggleNextPattern( int nPatternNumber ) {
614 if ( __song != nullptr && getMode() == Song::Mode::Pattern ) {
615 m_pAudioEngine->lock( RIGHT_HERE );
616 m_pAudioEngine->toggleNextPattern( nPatternNumber );
617 m_pAudioEngine->unlock();
619
620 } else {
621 ERRORLOG( "can't set next pattern in song mode" );
622 }
623}
624
625bool Hydrogen::flushAndAddNextPattern( int nPatternNumber ) {
626 if ( __song != nullptr && getMode() == Song::Mode::Pattern ) {
627 m_pAudioEngine->lock( RIGHT_HERE );
628 m_pAudioEngine->flushAndAddNextPattern( nPatternNumber );
629 m_pAudioEngine->unlock();
631
632 return true;
633
634 } else {
635 ERRORLOG( "can't set next pattern in song mode" );
636 }
637
638 return false;
639}
640
642{
643 m_pAudioEngine->restartAudioDrivers();
644}
645
646bool Hydrogen::startExportSession( int nSampleRate, int nSampleDepth,
647 double fCompressionLevel )
648{
649 AudioEngine* pAudioEngine = m_pAudioEngine;
650
651 if ( pAudioEngine->getState() == AudioEngine::State::Playing ) {
653 }
654
655 std::shared_ptr<Song> pSong = getSong();
656 if ( pSong == nullptr ) {
657 ERRORLOG( "No song set yet" );
658 return false;
659 }
660
661 m_oldEngineMode = pSong->getMode();
662 m_bOldLoopEnabled = pSong->isLoopEnabled();
663
664 pSong->setMode( Song::Mode::Song );
665 pSong->setLoopMode( Song::LoopMode::Disabled );
666
667 /*
668 * Currently an audio driver is loaded
669 * which is not the DiskWriter driver.
670 * Stop the current driver and fire up the DiskWriter.
671 */
672 pAudioEngine->stopAudioDrivers();
673
674 AudioOutput* pDriver = pAudioEngine->createAudioDriver(
676
677 DiskWriterDriver* pDiskWriterDriver = dynamic_cast<DiskWriterDriver*>( pDriver );
678 if ( pDriver == nullptr || pDiskWriterDriver == nullptr ) {
679 ERRORLOG( "Unable to start up DiskWriterDriver" );
680
681 if ( pDriver != nullptr ) {
682 delete pDriver;
683 }
684 return false;
685 }
686
687 pDiskWriterDriver->setSampleRate( static_cast<unsigned>(nSampleRate) );
688 pDiskWriterDriver->setSampleDepth( nSampleDepth );
689 pDiskWriterDriver->setCompressionLevel( fCompressionLevel );
690
692
693 return true;
694}
695
697void Hydrogen::startExportSong( const QString& filename)
698{
699 AudioEngine* pAudioEngine = m_pAudioEngine;
701 pAudioEngine->play();
702 pAudioEngine->getSampler()->stopPlayingNotes();
703
704 DiskWriterDriver* pDiskWriterDriver = static_cast<DiskWriterDriver*>(pAudioEngine->getAudioDriver());
705 pDiskWriterDriver->setFileName( filename );
706 pDiskWriterDriver->write();
707}
708
710{
711 AudioEngine* pAudioEngine = m_pAudioEngine;
712 pAudioEngine->getSampler()->stopPlayingNotes();
714}
715
717{
718 std::shared_ptr<Song> pSong = getSong();
719 if ( pSong == nullptr ) {
720 return;
721 }
722
723 pSong->setMode( m_oldEngineMode );
724 if ( m_bOldLoopEnabled ) {
725 pSong->setLoopMode( Song::LoopMode::Enabled );
726 } else {
727 pSong->setLoopMode( Song::LoopMode::Disabled );
728 }
729
730 AudioEngine* pAudioEngine = m_pAudioEngine;
731
732 pAudioEngine->stop();
733 pAudioEngine->restartAudioDrivers();
734 if ( pAudioEngine->getAudioDriver() == nullptr ) {
735 ERRORLOG( "Unable to restart previous audio driver after exporting song." );
736 }
738}
739
742{
743 return m_pAudioEngine->getAudioDriver();
744}
745
748{
749 return m_pAudioEngine->getMidiDriver();
750}
751
753{
754 return m_pAudioEngine->getMidiOutDriver();
755}
756
757// This will check if an instrument has any notes
758bool Hydrogen::instrumentHasNotes( std::shared_ptr<Instrument> pInst )
759{
760 std::shared_ptr<Song> pSong = getSong();
761 if ( pSong == nullptr ) {
762 return false;
763 }
764
765 PatternList* pPatternList = pSong->getPatternList();
766
767 for ( int nPattern = 0 ; nPattern < (int)pPatternList->size() ; ++nPattern )
768 {
769 if( pPatternList->get( nPattern )->references( pInst ) )
770 {
771 INFOLOG("Instrument " + pInst->get_name() + " has notes" );
772 return true;
773 }
774 }
775
776 // no notes for this instrument
777 return false;
778}
779
780void Hydrogen::removeInstrument( int nInstrumentNumber ) {
781 auto pSong = getSong();
782 if ( pSong != nullptr ) {
783
784 m_pAudioEngine->lock( RIGHT_HERE );
785
786 pSong->removeInstrument( nInstrumentNumber, false );
787
788 if ( nInstrumentNumber == m_nSelectedInstrumentNumber ) {
789 setSelectedInstrumentNumber( std::max( 0, nInstrumentNumber - 1 ) );
790 } else if ( m_nSelectedInstrumentNumber >=
791 pSong->getInstrumentList()->size() ) {
792 setSelectedInstrumentNumber( std::max( 0, pSong->getInstrumentList()->size() - 1 ) );
793 }
794 m_pAudioEngine->unlock();
795
796 setIsModified( true );
797 }
798}
799
800void Hydrogen::raiseError( unsigned nErrorCode )
801{
802 m_pAudioEngine->raiseError( nErrorCode );
803}
804
806{
807#ifndef WIN32
808 INFOLOG( "tap tempo" );
809 static timeval oldTimeVal;
810
811 struct timeval now;
812 gettimeofday(&now, nullptr);
813
814 float fInterval =
815 (now.tv_sec - oldTimeVal.tv_sec) * 1000.0
816 + (now.tv_usec - oldTimeVal.tv_usec) / 1000.0;
817
818 oldTimeVal = now;
819
820 // We multiply by a factor of two in order to allow for tempi
821 // smaller than the minimum one enter the calculation of the
822 // average. Else the minimum one could not be reached via tap
823 // tempo and it is clambed anyway.
824 if ( fInterval < 60000.0 * 2 / static_cast<float>(MIN_BPM) ) {
825 setTapTempo( fInterval );
826 }
827#endif
828}
829
830void Hydrogen::setTapTempo( float fInterval ) {
831
832 static float fOldBpm1 = -1;
833 static float fOldBpm2 = -1;
834 static float fOldBpm3 = -1;
835 static float fOldBpm4 = -1;
836 static float fOldBpm5 = -1;
837 static float fOldBpm6 = -1;
838 static float fOldBpm7 = -1;
839 static float fOldBpm8 = -1;
840
841 float fBPM = 60000.0 / fInterval;
842
843 if ( fabs( fOldBpm1 - fBPM ) > 20 ) { // troppa differenza, niente media
844 fOldBpm1 = fBPM;
845 fOldBpm2 = fBPM;
846 fOldBpm3 = fBPM;
847 fOldBpm4 = fBPM;
848 fOldBpm5 = fBPM;
849 fOldBpm6 = fBPM;
850 fOldBpm7 = fBPM;
851 fOldBpm8 = fBPM;
852 }
853
854 if ( fOldBpm1 == -1 ) {
855 fOldBpm1 = fBPM;
856 fOldBpm2 = fBPM;
857 fOldBpm3 = fBPM;
858 fOldBpm4 = fBPM;
859 fOldBpm5 = fBPM;
860 fOldBpm6 = fBPM;
861 fOldBpm7 = fBPM;
862 fOldBpm8 = fBPM;
863 }
864
865 fBPM = ( fBPM + fOldBpm1 + fOldBpm2 + fOldBpm3 + fOldBpm4 + fOldBpm5
866 + fOldBpm6 + fOldBpm7 + fOldBpm8 ) / 9.0;
867
868 INFOLOG( QString( "avg BPM = %1" ).arg( fBPM ) );
869 fOldBpm8 = fOldBpm7;
870 fOldBpm7 = fOldBpm6;
871 fOldBpm6 = fOldBpm5;
872 fOldBpm5 = fOldBpm4;
873 fOldBpm4 = fOldBpm3;
874 fOldBpm3 = fOldBpm2;
875 fOldBpm2 = fOldBpm1;
876 fOldBpm1 = fBPM;
877
878 m_pAudioEngine->lock( RIGHT_HERE );
879 m_pAudioEngine->setNextBpm( fBPM );
880 m_pAudioEngine->unlock();
881
882 // Store it's value in the .h2song file.
883 if ( __song != nullptr ) {
884 __song->setBpm( fBPM );
885 }
886
888}
889
891{
892 AudioEngine* pAudioEngine = m_pAudioEngine;
893
894 if ( pAudioEngine->getAudioDriver() ) {
895 pAudioEngine->lock( RIGHT_HERE );
896 pAudioEngine->setupLadspaFX();
897 pAudioEngine->unlock();
898 } else {
899 ERRORLOG( "m_pAudioDriver = NULL" );
900 }
901}
902
903void Hydrogen::updateSelectedPattern( bool bNeedsLock ) {
904 if ( isPatternEditorLocked() ) {
905 if ( bNeedsLock ) {
906 m_pAudioEngine->lock( RIGHT_HERE );
907 }
908 m_pAudioEngine->handleSelectedPattern();
909 if ( bNeedsLock ) {
910 m_pAudioEngine->unlock();
911 }
912 }
913}
914
915void Hydrogen::setSelectedPatternNumber( int nPat, bool bNeedsLock, bool bForce )
916{
917 if ( nPat == m_nSelectedPatternNumber ) {
918 if ( bForce ) {
920 }
921 return;
922 }
923
925 if ( bNeedsLock ) {
926 m_pAudioEngine->lock( RIGHT_HERE );
927 }
928
930 // The specific values provided are not important since we a
931 // in selected pattern mode.
932 m_pAudioEngine->updatePlayingPatterns();
933
934 if ( bNeedsLock ) {
935 m_pAudioEngine->unlock();
936 }
937 } else {
939 }
940
942}
943
944void Hydrogen::setSelectedInstrumentNumber( int nInstrument, bool bTriggerEvent )
945{
946 if ( m_nSelectedInstrumentNumber == nInstrument ) {
947 return;
948 }
949
950 m_nSelectedInstrumentNumber = nInstrument;
951
952 if ( bTriggerEvent ) {
954 }
955}
956
957void Hydrogen::renameJackPorts( std::shared_ptr<Song> pSong )
958{
959#ifdef H2CORE_HAVE_JACK
960 if ( pSong == nullptr ) {
961 return;
962 }
963
964 if ( Preferences::get_instance()->m_bJackTrackOuts == true &&
965 hasJackAudioDriver() && pSong != nullptr ) {
966
967 // When restarting the audio driver after loading a new song under
968 // Non session management all ports have to be registered _prior_
969 // to the activation of the client.
972 return;
973 }
974
975 m_pAudioEngine->makeTrackPorts( pSong );
976 }
977#endif
978}
979
982void Hydrogen::setbeatsToCount( int beatstocount)
983{
984 m_nbeatsToCount = beatstocount;
985}
986
988{
989 return m_nbeatsToCount;
990}
991
992void Hydrogen::setNoteLength( float notelength)
993{
994 m_ntaktoMeterCompute = notelength;
995}
996
998{
1000}
1001
1003{
1004 return m_nEventCount;
1005}
1006
1008{
1009 //individual fine tuning for the m_nBeatCounter
1010 //to adjust ms_offset from different people and controller
1011 Preferences *pPreferences = Preferences::get_instance();
1012
1013 m_nCoutOffset = pPreferences->m_countOffset;
1014 m_nStartOffset = pPreferences->m_startOffset;
1015}
1016
1018{
1019 AudioEngine* pAudioEngine = m_pAudioEngine;
1020
1021 // Get first time value:
1022 if (m_nBeatCount == 1) {
1023 gettimeofday(&m_CurrentTime,nullptr);
1024 }
1025
1026 m_nEventCount++;
1027
1028 // Set lastTime to m_CurrentTime to remind the time:
1029 timeval lastTime = m_CurrentTime;
1030
1031 // Get new time:
1032 gettimeofday(&m_CurrentTime,nullptr);
1033
1034
1035 // Build doubled time difference:
1036 double lastBeatTime = (double)(
1037 lastTime.tv_sec
1038 + (double)(lastTime.tv_usec * US_DIVIDER)
1039 + (int)m_nCoutOffset * .0001
1040 );
1041 double currentBeatTime = (double)(
1042 m_CurrentTime.tv_sec
1043 + (double)(m_CurrentTime.tv_usec * US_DIVIDER)
1044 );
1045 double beatDiff = m_nBeatCount == 1 ? 0 : currentBeatTime - lastBeatTime;
1046
1047 //if differences are to big reset the beatconter
1048 if( beatDiff > 3.001 * 1/m_ntaktoMeterCompute ) {
1049 m_nEventCount = 1;
1050 m_nBeatCount = 1;
1051 return false;
1052 }
1053 // Only accept differences big enough
1054 if (m_nBeatCount == 1 || beatDiff > .001) {
1055 if (m_nBeatCount > 1) {
1056 m_nBeatDiffs[m_nBeatCount - 2] = beatDiff ;
1057 }
1058 // Compute and reset:
1060 double beatTotalDiffs = 0;
1061 for(int i = 0; i < (m_nbeatsToCount - 1); i++) {
1062 beatTotalDiffs += m_nBeatDiffs[i];
1063 }
1064 double nBeatDiffAverage =
1065 beatTotalDiffs
1066 / (m_nBeatCount - 1)
1068 float fBeatCountBpm =
1069 (float) ((int) (60 / nBeatDiffAverage * 100))
1070 / 100;
1071
1072
1073 m_pAudioEngine->lock( RIGHT_HERE );
1074 m_pAudioEngine->setNextBpm( fBeatCountBpm );
1075 m_pAudioEngine->unlock();
1076
1077 if ( __song != nullptr ) {
1078 __song->setBpm( fBeatCountBpm );
1079 }
1080
1082
1083 if (Preferences::get_instance()->m_mmcsetplay
1085 m_nBeatCount = 1;
1086 m_nEventCount = 1;
1087 } else {
1088 if ( pAudioEngine->getState() != AudioEngine::State::Playing ){
1089 unsigned bcsamplerate =
1090 pAudioEngine->getAudioDriver()->getSampleRate();
1091 unsigned long rtstartframe = 0;
1092 if ( m_ntaktoMeterCompute <= 1){
1093 rtstartframe =
1094 bcsamplerate
1095 * nBeatDiffAverage
1096 * ( 1/ m_ntaktoMeterCompute );
1097 }else
1098 {
1099 rtstartframe =
1100 bcsamplerate
1101 * nBeatDiffAverage
1103 }
1104
1105 int sleeptime =
1106 ( (float) rtstartframe
1107 / (float) bcsamplerate
1108 * (int) 1000 )
1109 + (int)m_nCoutOffset
1110 + (int) m_nStartOffset;
1111
1112 std::this_thread::sleep_for( std::chrono::milliseconds( sleeptime ) );
1113
1115 }
1116
1117 m_nBeatCount = 1;
1118 m_nEventCount = 1;
1119 return true;
1120 }
1121 }
1122 else {
1123 m_nBeatCount ++;
1124 }
1125 }
1126 else {
1127 return false;
1128 }
1129 return true;
1130}
1131// ~ m_nBeatCounter
1132
1134{
1135#ifdef H2CORE_HAVE_JACK
1136 AudioEngine* pAudioEngine = m_pAudioEngine;
1137
1138 if ( hasJackTransport() ) {
1139 static_cast< JackAudioDriver* >( pAudioEngine->getAudioDriver() )->releaseTimebaseControl();
1140 }
1141#endif
1142}
1143
1145{
1146#ifdef H2CORE_HAVE_JACK
1147 AudioEngine* pAudioEngine = m_pAudioEngine;
1148
1149 if ( hasJackTransport() ) {
1150 static_cast< JackAudioDriver* >( pAudioEngine->getAudioDriver() )->initTimebaseControl();
1151 }
1152#endif
1153}
1154
1155void Hydrogen::addInstrumentToDeathRow( std::shared_ptr<Instrument> pInstr ) {
1156 __instrument_death_row.push_back( pInstr );
1158}
1159
1161{
1162 if ( __instrument_death_row.size() > 0 ) {
1163 std::shared_ptr<Instrument> pInstr = nullptr;
1164 while ( __instrument_death_row.size()
1165 && __instrument_death_row.front()->is_queued() == 0 ) {
1166 pInstr = __instrument_death_row.front();
1167 __instrument_death_row.pop_front();
1168 INFOLOG( QString( "Deleting unused instrument (%1). "
1169 "%2 unused remain." )
1170 . arg( pInstr->get_name() )
1171 . arg( __instrument_death_row.size() ) );
1172 pInstr = nullptr;
1173 }
1174 if ( __instrument_death_row.size() ) {
1175 pInstr = __instrument_death_row.front();
1176 INFOLOG( QString( "Instrument %1 still has %2 active notes. "
1177 "Delaying 'delete instrument' operation." )
1178 . arg( pInstr->get_name() )
1179 . arg( pInstr->is_queued() ) );
1180 }
1181 }
1182}
1183
1184
1185
1187{
1188 m_pAudioEngine->lock( RIGHT_HERE );
1190 m_pAudioEngine->getSampler()->stopPlayingNotes();
1191 m_pAudioEngine->unlock();
1192}
1193
1195#ifdef H2CORE_HAVE_JACK
1196 if ( m_pAudioEngine->getAudioDriver() != nullptr ) {
1197 if ( dynamic_cast<JackAudioDriver*>(m_pAudioEngine->getAudioDriver()) != nullptr ) {
1198 return true;
1199 }
1200 }
1201 return false;
1202#else
1203 return false;
1204#endif
1205}
1206
1208#ifdef H2CORE_HAVE_JACK
1209 if ( m_pAudioEngine->getAudioDriver() != nullptr ) {
1210 if ( dynamic_cast<JackAudioDriver*>(m_pAudioEngine->getAudioDriver()) != nullptr &&
1211 Preferences::get_instance()->m_bJackTransportMode ==
1213 return true;
1214 }
1215 }
1216 return false;
1217#else
1218 return false;
1219#endif
1220}
1221
1223#ifdef H2CORE_HAVE_JACK
1224 if ( m_pAudioEngine->getAudioDriver() != nullptr ) {
1225 if ( dynamic_cast<JackAudioDriver*>(m_pAudioEngine->getAudioDriver()) != nullptr ) {
1226 return static_cast<JackAudioDriver*>(m_pAudioEngine->getAudioDriver())->getTimebaseControllerBpm();
1227 } else {
1228 ERRORLOG("No JACK driver");
1229 return std::nan("");
1230 }
1231 } else {
1232 ERRORLOG("No audio driver");
1233 return std::nan("");
1234 }
1235#else
1236 ERRORLOG("No JACK support");
1237 return std::nan("");
1238#endif
1239}
1240
1242#ifdef H2CORE_HAVE_JACK
1243 AudioEngine* pAudioEngine = m_pAudioEngine;
1244 if ( hasJackTransport() ) {
1245 return static_cast<JackAudioDriver*>(pAudioEngine->getAudioDriver())->getTimebaseState();
1246 }
1248#else
1250#endif
1251}
1252
1254#ifdef H2CORE_HAVE_OSC
1255 if ( NsmClient::get_instance() != nullptr ) {
1256 if ( NsmClient::get_instance()->getUnderSessionManagement() ) {
1257 return true;
1258 } else {
1259 return false;
1260 }
1261 } else {
1262 return false;
1263 }
1264#else
1265 return false;
1266#endif
1267}
1268
1270 if ( __song != nullptr && __song->getIsTimelineActivated() &&
1273 return true;
1274 }
1275
1276 return false;
1277}
1278
1280 if ( getMode() == Song::Mode::Song &&
1281 __song != nullptr ) {
1282 if ( __song->getIsPatternEditorLocked() ) {
1283 return true;
1284 }
1285 }
1286
1287 return false;
1288}
1289
1291 if ( __song != nullptr &&
1292 bValue != __song->getIsPatternEditorLocked() ) {
1293 __song->setIsPatternEditorLocked( bValue );
1294 __song->setIsModified( true );
1295
1297
1299 bValue );
1300 }
1301}
1302
1304 if ( __song != nullptr ) {
1305 return __song->getMode();
1306 }
1307
1308 return Song::Mode::None;
1309}
1310
1312 if ( __song != nullptr && mode != __song->getMode() ) {
1313 __song->setMode( mode );
1315 ( mode == Song::Mode::Song) ? 1 : 0 );
1316 }
1317}
1318
1320 if ( __song != nullptr ) {
1321 return __song->getActionMode();
1322 }
1324}
1325
1327 if ( __song != nullptr ) {
1328 __song->setActionMode( mode );
1330 ( mode == Song::ActionMode::drawMode ) ? 1 : 0 );
1331 }
1332}
1333
1335 if ( __song != nullptr && getMode() == Song::Mode::Pattern ) {
1336 return __song->getPatternMode();
1337 }
1339}
1340
1342{
1343 if ( __song != nullptr &&
1344 getPatternMode() != mode ) {
1345 m_pAudioEngine->lock( RIGHT_HERE );
1346
1347 __song->setPatternMode( mode );
1348 setIsModified( true );
1349
1350 if ( m_pAudioEngine->getState() != AudioEngine::State::Playing ||
1351 mode == Song::PatternMode::Selected ) {
1352 // Only update the playing patterns in selected pattern
1353 // mode or if transport is not rolling. In stacked pattern
1354 // mode with transport rolling
1355 // AudioEngine::updatePatternTransportPosition() will call
1356 // the functions and activate the next patterns once the
1357 // current ones are looped.
1358 m_pAudioEngine->updatePlayingPatterns();
1359 m_pAudioEngine->clearNextPatterns();
1360 }
1361
1362 m_pAudioEngine->unlock();
1364 ( mode == Song::PatternMode::Selected ) ? 1 : 0 );
1365 }
1366}
1367
1370 return Tempo::Jack;
1371 }
1372 else if ( getMode() == Song::Mode::Song &&
1373 __song != nullptr && __song->getIsTimelineActivated() ) {
1374 return Tempo::Timeline;
1375 }
1376
1377 return Tempo::Song;
1378}
1379
1380void Hydrogen::toggleOscServer( bool bEnable ) {
1381#ifdef H2CORE_HAVE_OSC
1382 if ( bEnable ) {
1384 } else {
1386 }
1387#endif
1388}
1389
1391#ifdef H2CORE_HAVE_OSC
1392 OscServer* pOscServer = OscServer::get_instance();
1393 if( pOscServer ) {
1394 delete pOscServer;
1395 }
1396
1398
1399 if ( Preferences::get_instance()->getOscServerEnabled() ) {
1400 toggleOscServer( true );
1401 }
1402#endif
1403}
1404
1406{
1407#ifdef H2CORE_HAVE_OSC
1408 //NSM has to be started before jack driver gets created
1409 NsmClient* pNsmClient = NsmClient::get_instance();
1410
1411 if(pNsmClient){
1412 pNsmClient->createInitialClient();
1413 }
1414#endif
1415}
1416
1417
1419
1420 if ( !Preferences::get_instance()->getRubberBandBatchMode() ) {
1421 return;
1422 }
1423
1424 if ( getSong() != nullptr ) {
1425 auto pInstrumentList = getSong()->getInstrumentList();
1426 if ( pInstrumentList != nullptr ) {
1427 for ( unsigned nnInstr = 0; nnInstr < pInstrumentList->size(); ++nnInstr ) {
1428 auto pInstr = pInstrumentList->get( nnInstr );
1429 if ( pInstr == nullptr ) {
1430 return;
1431 }
1432 assert( pInstr );
1433 if ( pInstr != nullptr ){
1434 for ( int nnComponent = 0; nnComponent < pInstr->get_components()->size();
1435 ++nnComponent ) {
1436 auto pInstrumentComponent = pInstr->get_component( nnComponent );
1437 if ( pInstrumentComponent == nullptr ) {
1438 continue; // regular case when you have a new component empty
1439 }
1440
1441 for ( int nnLayer = 0; nnLayer < InstrumentComponent::getMaxLayers(); nnLayer++ ) {
1442 auto pLayer = pInstrumentComponent->get_layer( nnLayer );
1443 if ( pLayer != nullptr ) {
1444 auto pSample = pLayer->get_sample();
1445 if ( pSample != nullptr ) {
1446 if( pSample->get_rubberband().use ) {
1447 auto pNewSample = std::make_shared<Sample>( pSample );
1448
1449 if ( ! pNewSample->load( fBpm ) ){
1450 continue;
1451 }
1452
1453 // insert new sample from newInstrument
1454 pLayer->set_sample( pNewSample );
1455 }
1456 }
1457 }
1458 }
1459 }
1460 }
1461 }
1462 setIsModified( true );
1463 } else {
1464 ERRORLOG( "No InstrumentList present" );
1465 }
1466 } else {
1467 ERRORLOG( "No song set" );
1468 }
1469}
1470
1471void Hydrogen::setIsModified( bool bIsModified ) {
1472 if ( getSong() != nullptr ) {
1473 if ( getSong()->getIsModified() != bIsModified ) {
1474 getSong()->setIsModified( bIsModified );
1475 }
1476 }
1477}
1479 if ( getSong() != nullptr ) {
1480 return getSong()->getIsModified();
1481 }
1482 return false;
1483}
1484
1486 if ( getSong() != nullptr ) {
1487 return getSong()->getLastLoadedDrumkitPath();
1488 }
1489 ERRORLOG( "no song set yet" );
1490
1491 return "";
1492}
1493
1495 if ( getSong() != nullptr ) {
1496 return getSong()->getLastLoadedDrumkitName();
1497 }
1498 ERRORLOG( "no song set yet" );
1499
1500 return "";
1501}
1502
1504 if ( getSong() != nullptr ) {
1505 auto pPref = Preferences::get_instance();
1506 auto pAudioEngine = getAudioEngine();
1507
1508 if ( bEnabled != getSong()->getIsTimelineActivated() ) {
1509
1510 pAudioEngine->lock( RIGHT_HERE );
1511
1512 // DEBUGLOG( QString( "bEnabled: %1, getSong()->getIsTimelineActivated(): %2" )
1513 // .arg( bEnabled )
1514 // .arg( getSong()->getIsTimelineActivated()) );
1515
1516 pPref->setUseTimelineBpm( bEnabled );
1517 getSong()->setIsTimelineActivated( bEnabled );
1518
1519 if ( bEnabled ) {
1520 getTimeline()->activate();
1521 } else {
1522 getTimeline()->deactivate();
1523 }
1524
1525 pAudioEngine->handleTimelineChange();
1526 pAudioEngine->unlock();
1527
1528 EventQueue::get_instance()->push_event( EVENT_TIMELINE_ACTIVATION, static_cast<int>( bEnabled ) );
1529 }
1530 }
1531}
1532
1533int Hydrogen::getColumnForTick( long nTick, bool bLoopMode, long* pPatternStartTick ) const
1534{
1535 std::shared_ptr<Song> pSong = getSong();
1536 if ( pSong == nullptr ) {
1537 // Fallback
1538 const int nPatternSize = MAX_NOTES;
1539 const int nColumn = static_cast<int>(
1540 std::floor( static_cast<float>( nTick ) /
1541 static_cast<float>( nPatternSize ) ) );
1542 *pPatternStartTick = static_cast<long>(nColumn * nPatternSize);
1543 return nColumn;
1544 }
1545
1546 long nTotalTick = 0;
1547
1548 std::vector<PatternList*> *pPatternColumns = pSong->getPatternGroupVector();
1549 int nColumns = pPatternColumns->size();
1550
1551 if ( nColumns == 0 ) {
1552 // There are no patterns in the current song.
1553 *pPatternStartTick = 0;
1554 return 0;
1555 }
1556
1557 // Sum the lengths of all pattern columns and use the macro
1558 // MAX_NOTES in case some of them are of size zero. If the
1559 // supplied value nTick is bigger than this and doesn't belong to
1560 // the next pattern column, we just found the pattern list we were
1561 // searching for.
1562 int nPatternSize;
1563 for ( int i = 0; i < nColumns; ++i ) {
1564 PatternList *pColumn = ( *pPatternColumns )[ i ];
1565 if ( pColumn->size() != 0 ) {
1566 nPatternSize = pColumn->longest_pattern_length();
1567 } else {
1568 nPatternSize = MAX_NOTES;
1569 }
1570
1571 if ( ( nTick >= nTotalTick ) && ( nTick < nTotalTick + nPatternSize ) ) {
1572 ( *pPatternStartTick ) = nTotalTick;
1573 return i;
1574 }
1575 nTotalTick += nPatternSize;
1576 }
1577
1578 // If the song is played in loop mode, the tick numbers of the
1579 // second turn are added on top of maximum tick number of the
1580 // song. Therefore, we will introduced periodic boundary
1581 // conditions and start the search again.
1582 if ( bLoopMode ) {
1583 long nLoopTick = 0;
1584 // nTotalTicks is now the same as m_nSongSizeInTicks
1585 if ( nTotalTick != 0 ) {
1586 nLoopTick = nTick % nTotalTick;
1587 }
1588 nTotalTick = 0;
1589 for ( int i = 0; i < nColumns; ++i ) {
1590 PatternList *pColumn = ( *pPatternColumns )[ i ];
1591 if ( pColumn->size() != 0 ) {
1592 nPatternSize = pColumn->longest_pattern_length();
1593 } else {
1594 nPatternSize = MAX_NOTES;
1595 }
1596
1597 if ( ( nLoopTick >= nTotalTick )
1598 && ( nLoopTick < nTotalTick + nPatternSize ) ) {
1599 ( *pPatternStartTick ) = nTotalTick;
1600 return i;
1601 }
1602 nTotalTick += nPatternSize;
1603 }
1604 }
1605
1606 ( *pPatternStartTick ) = 0;
1607 return -1;
1608}
1609
1610long Hydrogen::getTickForColumn( int nColumn ) const
1611{
1612 auto pSong = getSong();
1613 if ( pSong == nullptr ) {
1614 // Fallback
1615 return static_cast<long>(nColumn * MAX_NOTES);
1616 }
1617
1618 const int nPatternGroups = pSong->getPatternGroupVector()->size();
1619 if ( nPatternGroups == 0 ) {
1620 // No patterns in song.
1621 return 0;
1622 }
1623
1624 if ( nColumn >= nPatternGroups ) {
1625 // The position is beyond the end of the Song, we
1626 // set periodic boundary conditions or return the
1627 // beginning of the Song as a fallback.
1628 if ( pSong->isLoopEnabled() ) {
1629 nColumn = nColumn % nPatternGroups;
1630 } else {
1631 WARNINGLOG( QString( "Provided column [%1] is larger than the available number [%2]")
1632 .arg( nColumn ) .arg( nPatternGroups )
1633 );
1634 return -1;
1635 }
1636 }
1637
1638 std::vector<PatternList*> *pColumns = pSong->getPatternGroupVector();
1639 long totalTick = 0;
1640 int nPatternSize;
1641 Pattern *pPattern = nullptr;
1642
1643 for ( int i = 0; i < nColumn; ++i ) {
1644 PatternList *pColumn = ( *pColumns )[ i ];
1645
1646 if( pColumn->size() > 0)
1647 {
1648 nPatternSize = pColumn->longest_pattern_length();
1649 } else {
1650 nPatternSize = MAX_NOTES;
1651 }
1652 totalTick += nPatternSize;
1653 }
1654
1655 return totalTick;
1656}
1657
1661
1662std::shared_ptr<Instrument> Hydrogen::getSelectedInstrument() const {
1663
1664 std::shared_ptr<Instrument> pInstrument = nullptr;
1665
1666 if ( __song != nullptr ) {
1667
1668 m_pAudioEngine->lock( RIGHT_HERE );
1669
1670 int nSelectedInstrumentNumber = m_nSelectedInstrumentNumber;
1671 auto pInstrList = __song->getInstrumentList();
1672 if ( nSelectedInstrumentNumber >= pInstrList->size() ) {
1673 nSelectedInstrumentNumber = -1;
1674 }
1675
1676 if ( nSelectedInstrumentNumber != -1 ) {
1677 pInstrument = pInstrList->get( nSelectedInstrumentNumber );
1678 }
1679
1680 m_pAudioEngine->unlock();
1681 }
1682
1683 return pInstrument;
1684}
1685
1687
1688 if ( __song == nullptr ) {
1689 ERRORLOG( "no song" );
1690 return;
1691 }
1692 PatternList *pPatternList = __song->getPatternList();
1693 if ( pPatternList == nullptr ) {
1694 ERRORLOG( "no pattern list");
1695 return;
1696 }
1697
1698 pPatternList->flattened_virtual_patterns_compute();
1699
1700 m_pAudioEngine->lock( RIGHT_HERE );
1701 m_pAudioEngine->updateVirtualPatterns();
1702 m_pAudioEngine->unlock();
1703
1705}
1706
1707QString Hydrogen::toQString( const QString& sPrefix, bool bShort ) const {
1708
1709 QString s = Base::sPrintIndention;
1710 QString sOutput;
1711 if ( ! bShort ) {
1712 sOutput = QString( "%1[Hydrogen]\n" ).arg( sPrefix )
1713 .append( QString( "%1%2__song: " ).arg( sPrefix ).arg( s ) );
1714 if ( __song != nullptr ) {
1715 sOutput.append( QString( "%1" ).arg( __song->toQString( sPrefix + s, bShort ) ) );
1716 } else {
1717 sOutput.append( QString( "nullptr\n" ) );
1718 }
1719 sOutput.append( QString( "%1%2m_ntaktoMeterCompute: %3\n" ).arg( sPrefix ).arg( s ).arg( m_ntaktoMeterCompute ) )
1720 .append( QString( "%1%2m_nbeatsToCount: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nbeatsToCount ) )
1721 .append( QString( "%1%2m_nEventCount: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nEventCount ) )
1722 .append( QString( "%1%2m_nTempoChangeCounter: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nTempoChangeCounter ) )
1723 .append( QString( "%1%2m_nBeatCount: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nBeatCount ) )
1724 .append( QString( "%1%2m_nBeatDiffs: [" ).arg( sPrefix ).arg( s ) );
1725 for ( auto dd : m_nBeatDiffs ) {
1726 sOutput.append( QString( " %1" ).arg( dd ) );
1727 }
1728 sOutput.append( QString( "]\n%1%2m_CurrentTime: %3" ).arg( sPrefix ).arg( s ).arg( static_cast<long>(m_CurrentTime.tv_sec ) ) )
1729 .append( QString( "%1%2m_nCoutOffset: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nCoutOffset ) )
1730 .append( QString( "%1%2m_nStartOffset: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nStartOffset ) )
1731 .append( QString( "%1%2m_oldEngineMode: %3\n" ).arg( sPrefix ).arg( s )
1732 .arg( static_cast<int>(m_oldEngineMode) ) )
1733 .append( QString( "%1%2m_bOldLoopEnabled: %3\n" ).arg( sPrefix ).arg( s ).arg( m_bOldLoopEnabled ) )
1734 .append( QString( "%1%2m_bExportSessionIsActive: %3\n" ).arg( sPrefix ).arg( s ).arg( m_bExportSessionIsActive ) )
1735 .append( QString( "%1%2m_GUIState: %3\n" ).arg( sPrefix ).arg( s ).arg( static_cast<int>( m_GUIState ) ) )
1736 .append( QString( "%1%2m_pTimeline:\n" ).arg( sPrefix ).arg( s ) );
1737 if ( m_pTimeline != nullptr ) {
1738 sOutput.append( QString( "%1" ).arg( m_pTimeline->toQString( sPrefix + s, bShort ) ) );
1739 } else {
1740 sOutput.append( QString( "nullptr\n" ) );
1741 }
1742 sOutput.append( QString( "%1%2__instrument_death_row:\n" ).arg( sPrefix ).arg( s ) );
1743 for ( auto const& ii : __instrument_death_row ) {
1744 if ( ii != nullptr ) {
1745 sOutput.append( QString( "%1" ).arg( ii->toQString( sPrefix + s + s, bShort ) ) );
1746 } else {
1747 sOutput.append( QString( "nullptr\n" ) );
1748 }
1749 }
1750 sOutput.append( QString( "%1%2m_nSelectedInstrumentNumber: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nSelectedInstrumentNumber ) )
1751 .append( QString( "%1%2m_pAudioEngine:\n" ).arg( sPrefix ).arg( s ) );
1752 if ( m_pAudioEngine != nullptr ) {
1753 sOutput.append( QString( "%1" )
1754 .arg( m_pAudioEngine->toQString( sPrefix + s + s, bShort ) ) );
1755 } else {
1756 sOutput.append( QString( "nullptr\n" ) );
1757 }
1758 sOutput.append( QString( "%1%2lastMidiEvent: %3\n" ).arg( sPrefix ).arg( s )
1760 .append( QString( "%1%2lastMidiEventParameter: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nLastMidiEventParameter ) )
1761 .append( QString( "%1%2m_nHihatOpenness: %3\n" ).arg( sPrefix )
1762 .arg( s ).arg( m_nHihatOpenness ) )
1763 .append( QString( "%1%2m_nInstrumentLookupTable: [ %3 ... %4 ]\n" ).arg( sPrefix ).arg( s )
1765 }
1766 else {
1767
1768 sOutput = QString( "%1[Hydrogen]" ).arg( sPrefix )
1769 .append( QString( ", __song: " ) );
1770 if ( __song != nullptr ) {
1771 sOutput.append( QString( "%1" ).arg( __song->toQString( sPrefix + s, bShort ) ) );
1772 } else {
1773 sOutput.append( QString( "nullptr" ) );
1774 }
1775 sOutput.append( QString( ", m_ntaktoMeterCompute: %1" ).arg( m_ntaktoMeterCompute ) )
1776 .append( QString( ", m_nbeatsToCount: %1" ).arg( m_nbeatsToCount ) )
1777 .append( QString( ", m_nEventCount: %1" ).arg( m_nEventCount ) )
1778 .append( QString( ", m_nTempoChangeCounter: %1" ).arg( m_nTempoChangeCounter ) )
1779 .append( QString( ", m_nBeatCount: %1" ).arg( m_nBeatCount ) )
1780 .append( QString( ", m_nBeatDiffs: [" ) );
1781 for ( auto dd : m_nBeatDiffs ) {
1782 sOutput.append( QString( " %1" ).arg( dd ) );
1783 }
1784 sOutput.append( QString( "], m_CurrentTime: %1" ).arg( static_cast<long>( m_CurrentTime.tv_sec ) ) )
1785 .append( QString( ", m_nCoutOffset: %1" ).arg( m_nCoutOffset ) )
1786 .append( QString( ", m_nStartOffset: %1" ).arg( m_nStartOffset ) )
1787 .append( QString( ", m_oldEngineMode: %1" )
1788 .arg( static_cast<int>(m_oldEngineMode) ) )
1789 .append( QString( ", m_bOldLoopEnabled: %1" ).arg( m_bOldLoopEnabled ) )
1790 .append( QString( ", m_bExportSessionIsActive: %1" ).arg( m_bExportSessionIsActive ) )
1791 .append( QString( ", m_GUIState: %1" ).arg( static_cast<int>( m_GUIState ) ) );
1792 sOutput.append( QString( ", m_pTimeline: " ) );
1793 if ( m_pTimeline != nullptr ) {
1794 sOutput.append( QString( "%1" ).arg( m_pTimeline->toQString( sPrefix, bShort ) ) );
1795 } else {
1796 sOutput.append( QString( "nullptr" ) );
1797 }
1798 sOutput.append( QString( ", __instrument_death_row: [" ) );
1799 for ( auto const& ii : __instrument_death_row ) {
1800 if ( ii != nullptr ) {
1801 sOutput.append( QString( "%1" ).arg( ii->toQString( sPrefix + s + s, bShort ) ) );
1802 } else {
1803 sOutput.append( QString( " nullptr" ) );
1804 }
1805 }
1806 sOutput.append( QString( ", m_nSelectedInstrumentNumber: %1" ).arg( m_nSelectedInstrumentNumber ) )
1807 .append( ", m_pAudioEngine:" );
1808 if ( m_pAudioEngine != nullptr ) {
1809 sOutput.append( QString( "%1" )
1810 .arg( m_pAudioEngine->toQString( sPrefix, bShort ) ) );
1811 } else {
1812 sOutput.append( QString( " nullptr" ) );
1813 }
1814 sOutput.append( QString( ", lastMidiEvent: %1" )
1816 .append( QString( ", lastMidiEventParameter: %1" )
1818 .append( QString( ", m_nHihatOpenness: %1" ).arg( m_nHihatOpenness ) )
1819 .append( QString( ", m_nInstrumentLookupTable: [ %1 ... %2 ]" )
1821 }
1822
1823 return sOutput;
1824}
1825
1826}; /* Namespace */
#define RIGHT_HERE
Macro intended to be used for the logging of the locking of the H2Core::AudioEngine.
Definition AudioEngine.h:61
#define INFOLOG(x)
Definition Object.h:240
#define WARNINGLOG(x)
Definition Object.h:241
#define ERRORLOG(x)
Definition Object.h:242
#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:99
@ Initialized
Not ready, but most pointers are now valid or NULL.
@ Playing
Transport is rolling.
void play()
Marks the audio engine to be started during the next call of the audioEngine_process() callback funct...
AudioOutput * createAudioDriver(const Preferences::AudioDriver &driver)
Create an audio driver using audioEngine_process() as its argument based on the provided choice and c...
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.
const std::shared_ptr< TransportPosition > getTransportPosition() 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 setCompressionLevel(double fCompressionLevel)
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
Hydrogen Audio Engine.
Definition Hydrogen.h:54
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:550
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:539
void initBeatcounter()
Auxiliary function setting a bunch of global variables.
Definition Hydrogen.cpp:209
JackAudioDriver::Timebase getJackTimebaseState() const
std::shared_ptr< Timeline > m_pTimeline
Local instance of the Timeline object.
Definition Hydrogen.h:555
void midi_noteOn(Note *note)
Definition Hydrogen.cpp:366
int m_nSelectedPatternNumber
Index of the pattern selected in the GUI or by a MIDI event.
Definition Hydrogen.h:576
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:532
void restartDrivers()
Definition Hydrogen.cpp:641
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.
Definition Hydrogen.h:66
@ Jack
Hydrogen will disregard all internal tempo settings and uses the ones provided by the JACK server ins...
Definition Hydrogen.h:72
@ Song
BeatCounter, TapTempo, OSC and MIDI commands as well as the BPM widget in the PlayerControl are used ...
Definition Hydrogen.h:64
bool hasJackAudioDriver() const
void sequencer_stop()
Stop the internal sequencer.
Definition Hydrogen.cpp:231
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:957
~Hydrogen()
Destructor taking care of most of the clean up.
Definition Hydrogen.cpp:155
std::shared_ptr< Song > getSong() const
Get the current song.
Definition Hydrogen.h:123
int m_nSelectedInstrumentNumber
Instrument currently focused/selected in the GUI.
Definition Hydrogen.h:572
void toggleNextPattern(int nPatternNumber)
Wrapper around AudioEngine::toggleNextPattern().
Definition Hydrogen.cpp:613
QString getLastLoadedDrumkitPath() const
std::list< std::shared_ptr< Instrument > > __instrument_death_row
Deleting instruments too soon leads to potential crashes.
Definition Hydrogen.h:562
void removeInstrument(int nInstrumentNumber)
Delete an Instrument.
Definition Hydrogen.cpp:780
void setBcOffsetAdjust()
void setIsTimelineActivated(bool bEnabled)
Wrapper around both Song::setIsTimelineActivated (recent) and Preferences::setUseTimelinebpm() (forme...
int m_nInstrumentLookupTable[MAX_INSTRUMENTS]
midi lookuptable
Definition Hydrogen.h:461
bool addRealtimeNote(int instrument, float velocity, bool noteoff=false, int msg1=0)
Definition Hydrogen.cpp:371
void stopExportSession()
Definition Hydrogen.cpp:716
int getSelectedInstrumentNumber() const
Definition Hydrogen.h:678
void setPatternMode(Song::PatternMode mode)
Wrapper around Song::setPatternMode() which also triggers EVENT_STACKED_MODE_ACTIVATION and should be...
void onTapTempoAccelEvent()
Definition Hydrogen.cpp:805
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:293
MidiInput * getMidiInput() const
Used to display midi driver info.
Definition Hydrogen.cpp:747
bool flushAndAddNextPattern(int nPatternNumber)
Wrapper around AudioEngine::flushAndAddNextPattern().
Definition Hydrogen.cpp:625
void setbeatsToCount(int beatstocount)
Updates m_nbeatsToCount.
Definition Hydrogen.cpp:982
GUIState
Specifies the state of the Qt GUI.
Definition Hydrogen.h:399
@ unavailable
No GUI available.
Definition Hydrogen.h:403
@ ready
There is a working GUI.
Definition Hydrogen.h:405
Song::PlaybackTrack getPlaybackTrackState() const
Wrapper around Song::getPlaybackTrackState().
Definition Hydrogen.cpp:245
int m_nLastRecordedMIDINoteTick
Onset of the recorded last in addRealtimeNote().
Definition Hydrogen.h:605
float m_ntaktoMeterCompute
beatcounter note length
Definition Hydrogen.h:524
std::shared_ptr< Song > __song
Pointer to the current song.
Definition Hydrogen.h:508
void setTapTempo(float fInterval)
Definition Hydrogen.cpp:830
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:529
Song::Mode getMode() const
static void create_instance()
Creates all the instances used within Hydrogen in the right order.
Definition Hydrogen.cpp:184
void updateVirtualPatterns()
Processes the patterns added to any virtual ones in the PatternList of the current Song and ensure bo...
void setSelectedInstrumentNumber(int nInstrument, bool bTriggerEvent=true)
Definition Hydrogen.cpp:944
void restartLadspaFX()
Definition Hydrogen.cpp:890
std::shared_ptr< Timeline > getTimeline() const
Definition Hydrogen.h:644
SoundLibraryDatabase * m_pSoundLibraryDatabase
Definition Hydrogen.h:611
void mutePlaybackTrack(const bool bMuted)
Wrapper around Song::setPlaybackTrackEnabled().
Definition Hydrogen.cpp:255
AudioEngine * m_pAudioEngine
Central instance of the audio engine.
Definition Hydrogen.h:609
MidiMessage::Event m_lastMidiEvent
Cache last incoming MIDI event to be used in MidiSenseWidget.
Definition Hydrogen.h:635
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:84
Song::PatternMode getPatternMode() const
static Hydrogen * __instance
Static reference to the Hydrogen singleton.
Definition Hydrogen.h:501
void __kill_instruments()
void updateSelectedPattern(bool bNeedsLock=true)
Updates the selected pattern to the one recorded note will be inserted to.
Definition Hydrogen.cpp:903
float getJackTimebaseControllerBpm() const
void setIsPatternEditorLocked(bool bValue)
MidiOutput * getMidiOutput() const
Definition Hydrogen.cpp:752
void startExportSong(const QString &filename)
Export a song to a wav file.
Definition Hydrogen.cpp:697
int m_nTempoChangeCounter
count tempochanges for timeArray
Definition Hydrogen.h:527
int m_nbeatsToCount
beatcounter beats to count
Definition Hydrogen.h:525
bool handleBeatCounter()
int m_nEventCount
beatcounter event
Definition Hydrogen.h:526
AudioEngine * getAudioEngine() const
Definition Hydrogen.h:663
void setNoteLength(float notelength)
Definition Hydrogen.cpp:992
void releaseJackTimebaseControl()
Calling JackAudioDriver::releaseTimebaseControl() directly from the GUI.
std::shared_ptr< Instrument > getSelectedInstrument() const
int m_nHihatOpenness
Controls the instrument selection within a hihat group.
Definition Hydrogen.h:614
int m_nLastMidiEventParameter
Definition Hydrogen.h:636
void loadPlaybackTrack(QString sFilename)
Wrapper function for loading the playback track.
Definition Hydrogen.cpp:267
AudioOutput * getAudioOutput() const
Used to display audio driver info.
Definition Hydrogen.cpp:741
bool m_bOldLoopEnabled
Definition Hydrogen.h:538
void setIsModified(bool bIsModified)
Wrapper around Song::setIsModified() that checks whether a song is set.
void initJackTimebaseControl()
Calling JackAudioDriver::initTimebaseControl() directly from the GUI.
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:758
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
void setSessionDrumkitNeedsRelinking(bool bNeedsRelinking)
Definition Hydrogen.h:683
bool isPatternEditorLocked() const
Convenience function checking whether using the Pattern Editor is locked in the song settings and the...
void stopExportSong()
Definition Hydrogen.cpp:709
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:915
bool hasJackTransport() const
float getNoteLength()
Definition Hydrogen.cpp:997
void toggleOscServer(bool bEnable)
Starts/stops the OSC server.
bool getIsModified() const
Wrapper around Song::getIsModified() that checks whether a song is set.
bool startExportSession(int nSampleRate, int nSampleDepth, double fCompressionLevel=0.0)
Definition Hydrogen.cpp:646
timeval m_CurrentTime
timeval
Definition Hydrogen.h:530
QString getLastLoadedDrumkitName() const
CoreActionController * getCoreActionController() const
Definition Hydrogen.h:653
Song::Mode m_oldEngineMode
ms default 0
Definition Hydrogen.h:537
CoreActionController * m_pCoreActionController
Local instance of the CoreActionController object.
Definition Hydrogen.h:559
void raiseError(unsigned nErrorCode)
Definition Hydrogen.cpp:800
int m_nBeatCount
beatcounter beat to count
Definition Hydrogen.h:528
void sequencer_play()
Start the internal sequencer.
Definition Hydrogen.cpp:221
GUIState getGUIState() const
Definition Hydrogen.h:667
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.
void initTimebaseControl()
Acquires control of JACK Timebase.
float getTimebaseControllerBpm() const
void releaseTimebaseControl()
Release Hydrogen from the JACK Timebase control.
Timebase
Whether Hydrogen or another program is in Timebase control.
@ Listener
An external program is Timebase controller and Hydrogen will disregard all tempo markers on the Timel...
@ None
Only normal clients registered.
Timebase getTimebaseState() const
static Logger * create_instance(const QString &sLogFilePath=QString(), bool bUseStdout=true, bool bLogTimestamps=false, bool bLogColors=true)
If __instance equals 0, a new H2Core::Logger singleton will be created and stored in it.
Definition Logger.cpp:161
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:101
int get_position() const
__position accessor
Definition Note.h:534
void set_length(int value)
__length setter
Definition Note.h:554
std::shared_ptr< Instrument > get_instrument()
__instrument accessor
Definition Note.h:499
Key
possible keys
Definition Note.h:105
static double pitchToFrequency(double fPitch)
Convert a logarithmic pitch-space value in semitones to a frequency-domain value.
Definition Note.h:387
void set_note_off(bool value)
__note_off setter
Definition Note.h:574
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:109
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:250
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:79
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:90
void setRecordEvents(bool value)
void stopPlayingNotes(std::shared_ptr< Instrument > pInstr=nullptr)
Definition Sampler.cpp:1335
@ None
Used in case no song is set and both pattern and song editor are not ready to operate yet.
Definition Song.h:69
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.
Definition Song.h:80
@ None
Used in case no song is set and both pattern and song editor are not ready to operate yet.
Definition Song.h:83
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.
Definition Song.h:124
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.
Definition Song.h:110
@ Selected
Only one pattern - the one currently selected in the GUI - will be played back.
Definition Song.h:106
This class holds information about all installed soundlibrary items.
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