hydrogen 1.2.3
AudioEngine.h
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
23#ifndef AUDIO_ENGINE_H
24#define AUDIO_ENGINE_H
25
27
28#include <core/config.h>
29#include <core/Object.h>
30#include <core/Hydrogen.h>
32#include <core/Synth/Synth.h>
33#include <core/Basics/Note.h>
35
36#include <core/IO/AudioOutput.h>
39#include <core/IO/FakeDriver.h>
40
41#include <memory>
42#include <string>
43#include <cassert>
44#include <mutex>
45#include <thread>
46#include <chrono>
47#include <deque>
48#include <queue>
49
58#ifndef RIGHT_HERE
59#define RIGHT_HERE __FILE__, __LINE__, __PRETTY_FUNCTION__
60#endif
61
62typedef int ( *audioProcessCallback )( uint32_t, void * );
63
64namespace H2Core
65{
66 class MidiOutput;
67 class MidiInput;
68 class EventQueue;
69 class PatternList;
70 class Drumkit;
71 class Song;
72 class TransportPosition;
73
96class AudioEngine : public H2Core::Object<AudioEngine>
97{
99public:
100
101 enum class State {
105 Uninitialized = 1,
109 Initialized = 2,
113 Prepared = 3,
117 Ready = 4,
121 Playing = 5,
128 Testing = 6
129 };
130
139 static constexpr float fHumanizeVelocitySD = 0.2;
149 static constexpr float fHumanizePitchSD = 0.4;
159 static constexpr float fHumanizeTimingSD = 0.3;
164 static constexpr int nMaxTimeHumanize = 2000;
165
166 AudioEngine();
167
168 ~AudioEngine();
169
198 void lock( const char* file, unsigned int line, const char* function );
199
214 bool tryLock( const char* file,
215 unsigned int line,
216 const char* function );
217
234 bool tryLockFor( std::chrono::microseconds duration,
235 const char* file,
236 unsigned int line,
237 const char* function );
238
244 void unlock();
245
250 void assertLocked( );
251 void noteOn( Note *note );
252
264 static int audioEngine_process( uint32_t nframes, void *arg );
265
269 static float computeTickSize( const int nSampleRate, const float fBpm, const int nResolution);
270 static double computeDoubleTickSize(const int nSampleRate, const float fBpm, const int nResolution);
271
272 Sampler* getSampler() const;
273 Synth* getSynth() const;
274
276 float getElapsedTime() const;
277
282 void startAudioDrivers();
286 void stopAudioDrivers();
302 AudioOutput* createAudioDriver( const QString& sDriver );
303
304 void restartAudioDrivers();
305
306 void setupLadspaFX();
307
314 void renameJackPorts(std::shared_ptr<Song> pSong);
315
316 MidiInput* getMidiDriver() const;
318
319 std::shared_ptr<Instrument> getMetronomeInstrument() const;
320
321
322 void raiseError( unsigned nErrorCode );
323
324 State getState() const;
325
326 void setMasterPeak_L( float value );
327 float getMasterPeak_L() const;
328
329 void setMasterPeak_R( float value );
330 float getMasterPeak_R() const;
331
332 float getProcessTime() const;
333 float getMaxProcessTime() const;
334
335 const std::shared_ptr<TransportPosition> getTransportPosition() const;
336
337 const PatternList* getNextPatterns() const;
338 const PatternList* getPlayingPatterns() const;
339
340 long long getRealtimeFrame() const;
341
347 static double getLeadLagInTicks();
348
355 long long getLeadLagInFrames( double fTick );
356
357 double getSongSizeInTicks() const;
358
366 void play();
374 void stop();
375
383 void setNextBpm( float fNextBpm );
384 float getNextBpm() const;
385
386 static float getBpmAtColumn( int nColumn );
387
395 void updateSongSize();
396
397 void removePlayingPattern( Pattern* pPattern );
416 void clearNextPatterns();
421 void toggleNextPattern( int nPatternNumber );
428 void flushAndAddNextPattern( int nPatternNumber );
429
431
437 int getEnqueuedNotesNumber() const;
438
439 const QStringList getSupportedAudioDrivers() const;
440
449 QString toQString( const QString& sPrefix = "", bool bShort = true ) const override;
450
452 friend void Hydrogen::setSong( std::shared_ptr<Song> pSong, bool bRelinking );
454 friend void Hydrogen::removeSong();
463 friend bool CoreActionController::addTempoMarker( int, float );
466 friend bool CoreActionController::locateToTick( long nTick, bool );
473 friend class AudioEngineTests;
474private:
475
484
485 inline void processPlayNotes( unsigned long nframes );
486
487 void reset( bool bWithJackBroadcast = true );
488
489 void resetOffsets();
490
502 double coarseGrainTick( double fTick );
503
504 void clearNoteQueues();
507 void clearAudioBuffers( uint32_t nFrames );
513 void updateNoteQueue( unsigned nIntervalLengthInFrames );
514 void processAudio( uint32_t nFrames );
515 long long computeTickInterval( double* fTickStart, double* fTickEnd, unsigned nIntervalLengthInFrames );
516 void updateBpmAndTickSize( std::shared_ptr<TransportPosition> pTransportPosition );
517 void calculateTransportOffsetOnBpmChange( std::shared_ptr<TransportPosition> pTransportPosition );
518
519 void setRealtimeFrame( long long nFrame );
520 void updatePlayingPatternsPos( std::shared_ptr<TransportPosition> pPos );
521
522 void setSong( std::shared_ptr<Song>pNewSong );
523 void removeSong();
524 void setState( State state );
525 void setNextState( State state );
526 State getNextState() const;
527
528 void startPlayback();
529
530 void stopPlayback();
531
532 void locate( const double fTick, bool bWithJackBroadcast = true );
541 void locateToFrame( const long long nFrame );
542 void incrementTransportPosition( uint32_t nFrames );
543 bool isEndOfSongReached( std::shared_ptr<TransportPosition> pPos ) const;
544 void updateTransportPosition( double fTick, long long nFrame,
545 std::shared_ptr<TransportPosition> pPos );
546 void updateSongTransportPosition( double fTick, long long nFrame,
547 std::shared_ptr<TransportPosition> pPos );
548 void updatePatternTransportPosition( double fTick, long long nFrame,
549 std::shared_ptr<TransportPosition> pPos );
550
555 void handleTempoChange();
556
569
575
581 void handleDriverChange();
582
588
594
601
602 #if defined(H2CORE_HAVE_LADSPA) || _DOXYGEN_
605 #endif
606
607 //Master peak (left channel)
609
610 //Master peak (right channel)
612
621 std::timed_mutex m_EngineMutex;
622
633
637 std::thread::id m_LockingThread;
638
640 const char* file;
641 unsigned int line;
642 const char* function;
644
648
649 std::shared_ptr<TransportPosition> m_pTransportPosition;
650 std::shared_ptr<TransportPosition> m_pQueuingPosition;
651
654
664
674
676
678 // overload the > operator of Note objects for priority_queue
680 bool operator() (Note* pNote1, Note* pNote2);
681 };
682
683 std::priority_queue<Note*, std::deque<Note*>, compare_pNotes > m_songNoteQueue;
684 std::deque<Note*> m_midiNoteQueue;
685
689 std::shared_ptr<Instrument> m_pMetronomeInstrument;
690
694
699 void checkJackSupport();
700
706
708
712};
713
714
730
732
733protected:
737 void assertAudioEngineLocked() const;
738
739
740public:
741
747 void setNeedsLock( bool bNeedsLock ) {
748 m_bNeedsLock = bNeedsLock;
749 }
750
752 m_bNeedsLock = false;
753 }
754};
755
756
758#ifndef NDEBUG
759 assert( m_LockingThread == std::this_thread::get_id() );
760#endif
761}
762
763inline void AudioEngine::setMasterPeak_L( float value ) {
764 m_fMasterPeak_L = value;
765}
766
767inline float AudioEngine::getMasterPeak_L() const {
768 return m_fMasterPeak_L;
769}
770
771inline void AudioEngine::setMasterPeak_R( float value ) {
772 m_fMasterPeak_R = value;
773}
774
775inline float AudioEngine::getMasterPeak_R() const {
776 return m_fMasterPeak_R;
777}
778
779inline float AudioEngine::getProcessTime() const {
780 return m_fProcessTime;
781}
782
783inline float AudioEngine::getMaxProcessTime() const {
784 return m_fMaxProcessTime;
785}
786
788 return m_state;
789}
790
795 m_nextState = state;
796}
797
799 return m_pAudioDriver;
800}
801
803 return m_pMidiDriver;
804}
805
809
810inline long long AudioEngine::getRealtimeFrame() const {
811 return m_nRealtimeFrame;
812}
813
814inline void AudioEngine::setRealtimeFrame( long long nFrame ) {
815 m_nRealtimeFrame = nFrame;
816}
817
818inline float AudioEngine::getNextBpm() const {
819 return m_fNextBpm;
820}
821inline const std::shared_ptr<TransportPosition> AudioEngine::getTransportPosition() const {
823}
824inline double AudioEngine::getSongSizeInTicks() const {
825 return m_fSongSizeInTicks;
826}
827inline std::shared_ptr<Instrument> AudioEngine::getMetronomeInstrument() const {
829}
831 return m_songNoteQueue.size();
832}
833inline const QStringList AudioEngine::getSupportedAudioDrivers() const {
835}
836};
837
838#endif
int(* audioProcessCallback)(uint32_t, void *)
Definition AudioEngine.h:62
#define H2_OBJECT(name)
Definition Object.h:224
AudioEngineLocking.
void setNeedsLock(bool bNeedsLock)
The audio processing thread can modify some PatternLists.
void assertAudioEngineLocked() const
Assert that the AudioEngine lock is held if needed.
Defined in here since it requires access to methods and variables private to the #AudioEngine class.
The audio engine deals with two distinct #TransportPosition.
Definition AudioEngine.h:97
int m_nLoopsDone
Indicates how many loops the transport already did when the user presses the Loop button again.
void updateBpmAndTickSize(std::shared_ptr< TransportPosition > pTransportPosition)
float getMasterPeak_L() const
std::shared_ptr< Instrument > getMetronomeInstrument() const
void handleTimelineChange()
Updates the transport states and all notes in m_songNoteQueue and m_midiNoteQueue after adding or del...
void flushAndAddNextPattern(int nPatternNumber)
Add pattern nPatternNumber to #m_pNextPatterns as well as the whole content of #m_pPlayingPatterns.
std::shared_ptr< TransportPosition > m_pTransportPosition
MidiOutput * m_pMidiDriverOut
friend void Hydrogen::removeSong()
Is allowed to call removeSong().
void setRealtimeFrame(long long nFrame)
bool tryLock(const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
friend void Hydrogen::setSong(std::shared_ptr< Song > pSong, bool bRelinking)
Is allowed to call setSong().
AudioOutput * m_pAudioDriver
void handleSelectedPattern()
Keeps the selected pattern in line with the one the transport position resides in while in Song::Mode...
const PatternList * getNextPatterns() const
std::deque< Note * > m_midiNoteQueue
Midi Note FIFO.
static float getBpmAtColumn(int nColumn)
void clearAudioBuffers(uint32_t nFrames)
Clear all audio buffers.
void setNextState(State state)
void renameJackPorts(std::shared_ptr< Song > pSong)
Hands the provided Song to JackAudioDriver::makeTrackOutputs() if pSong is not a null pointer and the...
static constexpr float fHumanizePitchSD
Maximum value the standard deviation of the Gaussian distribution the random pitch contribution will ...
audioProcessCallback m_AudioProcessCallback
double getSongSizeInTicks() const
int getEnqueuedNotesNumber() const
Returns the size of m_songNoteQueue.
void setMasterPeak_R(float value)
void handleLoopModeChanged()
In order to properly support H2Core::Song::LoopMode::Finishing - transport was already looped a coupl...
void toggleNextPattern(int nPatternNumber)
Add pattern nPatternNumber to #m_pNextPatterns or deletes it in case it is already present.
void setState(State state)
std::timed_mutex m_EngineMutex
Mutex for synchronizing the access to the Song object and the AudioEngine.
void removePlayingPattern(Pattern *pPattern)
long long m_nRealtimeFrame
Variable keeping track of the transport position in realtime.
@ Prepared
Drivers are set up, but not ready to process audio.
@ Initialized
Not ready, but most pointers are now valid or NULL.
@ Playing
Transport is rolling.
@ Ready
Ready to process audio.
@ Uninitialized
Not even the constructors have been called.
@ Testing
State used during the unit tests of the AudioEngine.
float getElapsedTime() const
void setNextBpm(float fNextBpm)
Stores the new speed into a separate variable which will be adopted during the next processing cycle.
State m_nextState
State assigned during the next call to processTransport().
void locateToFrame(const long long nFrame)
Version of the locate() function intended to be directly used by frame-based audio drivers / servers.
void updatePlayingPatternsPos(std::shared_ptr< TransportPosition > pPos)
AudioOutput * createAudioDriver(const QString &sDriver)
Create an audio driver using audioEngine_process() as its argument based on the provided choice and c...
void checkJackSupport()
Attempts to dynamically load the JACK 2 shared library and stores the result in m_bJackSupported.
friend void JackAudioDriver::updateTransportPosition()
long long getLeadLagInFrames(double fTick)
Calculates lead lag factor (in frames) relative to the transport position fTick.
void play()
Marks the audio engine to be started during the next call of the audioEngine_process() callback funct...
float getProcessTime() const
float getNextBpm() const
static constexpr float fHumanizeTimingSD
Maximum value the standard deviation of the Gaussian distribution the random pitch contribution will ...
void updatePlayingPatterns()
Update the list of currently played patterns associated with m_pTransportPosition and m_pQueuingPosit...
static constexpr int nMaxTimeHumanize
Maximum time (in frames) a note's position can be off due to the humanization (lead-lag).
std::priority_queue< Note *, std::deque< Note * >, compare_pNotes > m_songNoteQueue
void handleTempoChange()
Updates all notes in m_songNoteQueue and m_midiNoteQueue to be still valid after a tempo change.
float m_fFXPeak_L[MAX_FX]
bool tryLockFor(std::chrono::microseconds duration, const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
const QStringList getSupportedAudioDrivers() const
State getNextState() const
bool m_bJackSupported
Whether or not the shared library of the JACK server could be found on the system at runtime.
void handleSongModeChanged()
Called whenever Hydrogen switches from Song::Mode::Song into Song::Mode::Pattern or the other way aro...
EventQueue * m_pEventQueue
QMutex m_MutexOutputPointer
Mutex for locking the pointer to the audio output buffer, allowing multiple readers.
float getMasterPeak_R() const
double m_fSongSizeInTicks
Set to the total number of ticks in a Song.
bool isEndOfSongReached(std::shared_ptr< TransportPosition > pPos) const
void stop()
Marks the audio engine to be stopped during the next call of the audioEngine_process() callback funct...
void calculateTransportOffsetOnBpmChange(std::shared_ptr< TransportPosition > pTransportPosition)
void unlock()
Mutex unlocking of the AudioEngine.
float getMaxProcessTime() const
void lock(const char *file, unsigned int line, const char *function)
Mutex locking of the AudioEngine.
State getState() const
const PatternList * getPlayingPatterns() const
State m_state
Current state of the H2Core::AudioEngine.
double coarseGrainTick(double fTick)
Ideally we just floor the provided tick.
static double getLeadLagInTicks()
Maximum lead lag factor in ticks.
std::shared_ptr< TransportPosition > m_pQueuingPosition
static constexpr float fHumanizeVelocitySD
Maximum value the standard deviation of the Gaussian distribution the random velocity contribution wi...
static float computeTickSize(const int nSampleRate, const float fBpm, const int nResolution)
Calculates the number of frames that make up a tick.
void updatePatternTransportPosition(double fTick, long long nFrame, std::shared_ptr< TransportPosition > pPos)
static int audioEngine_process(uint32_t nframes, void *arg)
Main audio processing function called by the audio drivers whenever there is work to do.
struct H2Core::AudioEngine::_locker_struct m_pLocker
void locate(const double fTick, bool bWithJackBroadcast=true)
QStringList m_supportedAudioDrivers
AudioOutput * getAudioDriver() const
void processPlayNotes(unsigned long nframes)
void updateSongSize()
Function to be called every time the length of the current song does change, e.g.
void assertLocked()
Assert that the calling thread is the current holder of the AudioEngine lock.
Sampler * getSampler() const
void stopAudioDrivers()
Stops all audio and MIDI drivers.
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)
std::shared_ptr< Instrument > m_pMetronomeInstrument
Pointer to the metronome.
void handleSongSizeChange()
Updates all notes in m_songNoteQueue to be still valid after a change in song size.
float m_fFXPeak_R[MAX_FX]
void handleDriverChange()
The audio driver was changed what possible changed the tick size - which depends on both the sample r...
void reset(bool bWithJackBroadcast=true)
MidiInput * m_pMidiDriver
void updateSongTransportPosition(double fTick, long long nFrame, std::shared_ptr< TransportPosition > pPos)
long long computeTickInterval(double *fTickStart, double *fTickEnd, unsigned nIntervalLengthInFrames)
void startAudioDrivers()
Creation and initialization of all audio and MIDI drivers called in Hydrogen::Hydrogen().
void processAudio(uint32_t nFrames)
Synth * getSynth() const
MidiOutput * getMidiOutDriver() const
void incrementTransportPosition(uint32_t nFrames)
void updateNoteQueue(unsigned nIntervalLengthInFrames)
Takes all notes from the currently playing patterns, from the MIDI queue m_midiNoteQueue,...
static double computeDoubleTickSize(const int nSampleRate, const float fBpm, const int nResolution)
void raiseError(unsigned nErrorCode)
long long getRealtimeFrame() const
MidiInput * getMidiDriver() const
std::thread::id m_LockingThread
Thread ID of the current holder of the AudioEngine lock.
void setMasterPeak_L(float value)
Base abstract class for audio output classes.
Definition AudioOutput.h:39
bool locateToTick(long nTick, bool bWithJackBroadcast=true)
Relocates transport to a particular tick.
bool deleteTempoMarker(int nPosition)
Delete a tempo marker from the Timeline.
bool activateSongMode(bool bActivate)
Switches between Song and Pattern mode of playback.
bool activateLoopMode(bool bActivate)
Toggle loop mode of playback.
bool addTempoMarker(int nPosition, float fBpm)
Adds a tempo marker to the Timeline.
Object handling the communication between the core of Hydrogen and its GUI.
Definition EventQueue.h:211
virtual int connect() override
void setIsTimelineActivated(bool bEnabled)
Wrapper around both Song::setIsTimelineActivated (recent) and Preferences::setUseTimelinebpm() (forme...
void setSong(std::shared_ptr< Song > newSong, bool bRelinking=true)
Sets the current song __song to newSong.
Definition Hydrogen.cpp:288
void updateSelectedPattern(bool bNeedsLock=true)
Updates the selected pattern to the one recorded note will be inserted to.
Definition Hydrogen.cpp:877
void updateTransportPosition()
The function queries the transport position and additional information from the JACK server,...
void relocateUsingBBT()
Uses the bar-beat-tick information to relocate the transport position.
MIDI input base class.
Definition MidiInput.h:39
MIDI input base class.
Definition MidiOutput.h:41
A note plays an associated instrument with a velocity left and right pan.
Definition Note.h:102
PatternList is a collection of patterns.
Definition PatternList.h:43
Pattern class is a Note container.
Definition Pattern.h:46
Waveform based sampler.
Definition Sampler.h:51
A simple synthetizer...
Definition Synth.h:43
#define MAX_FX
Maximum number of effects.
Definition config.dox:83
int(* audioProcessCallback)(uint32_t, void *)
Definition AudioOutput.h:32
bool operator()(Note *pNote1, Note *pNote2)