hydrogen 1.2.6
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-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
23#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>
36
37#include <core/IO/AudioOutput.h>
40#include <core/IO/FakeDriver.h>
41
42#include <memory>
43#include <string>
44#include <cassert>
45#include <mutex>
46#include <thread>
47#include <chrono>
48#include <deque>
49#include <queue>
50#include <QString>
51
60#ifndef RIGHT_HERE
61#define RIGHT_HERE __FILE__, __LINE__, __PRETTY_FUNCTION__
62#endif
63
64typedef int ( *audioProcessCallback )( uint32_t, void * );
65
66namespace H2Core
67{
68 class MidiOutput;
69 class MidiInput;
70 class EventQueue;
71 class PatternList;
72 class Drumkit;
73 class Song;
74 class TransportPosition;
75
98class AudioEngine : public H2Core::Object<AudioEngine>
99{
101public:
102
103 enum class State {
119 Ready = 4,
131 };
132 static QString StateToQString( const State& state );
133
142 static constexpr float fHumanizeVelocitySD = 0.2;
152 static constexpr float fHumanizePitchSD = 0.4;
162 static constexpr float fHumanizeTimingSD = 0.3;
167 static constexpr int nMaxTimeHumanize = 2000;
168
169 AudioEngine();
170
171 ~AudioEngine();
172
201 void lock( const char* file, unsigned int line, const char* function );
202
217 bool tryLock( const char* file,
218 unsigned int line,
219 const char* function );
220
237 bool tryLockFor( std::chrono::microseconds duration,
238 const char* file,
239 unsigned int line,
240 const char* function );
241
247 void unlock();
248
253 void assertLocked( const QString& sClass, const char* sFunction,
254 const QString& sMsg );
255 void noteOn( Note *note );
256
268 static int audioEngine_process( uint32_t nframes, void *arg );
269
273 static float computeTickSize( const int nSampleRate, const float fBpm, const int nResolution);
274 static double computeDoubleTickSize(const int nSampleRate, const float fBpm, const int nResolution);
275
276 Sampler* getSampler() const;
277 Synth* getSynth() const;
278
280 float getElapsedTime() const;
281
286 void startAudioDrivers();
290 void stopAudioDrivers();
306
307 void restartAudioDrivers();
308
309 void setupLadspaFX();
310
317 void renameJackPorts(std::shared_ptr<Song> pSong);
318
319 MidiInput* getMidiDriver() const;
321
322 std::shared_ptr<Instrument> getMetronomeInstrument() const;
323
324
325 void raiseError( unsigned nErrorCode );
326
327 State getState() const;
328
329 void setMasterPeak_L( float value );
330 float getMasterPeak_L() const;
331
332 void setMasterPeak_R( float value );
333 float getMasterPeak_R() const;
334
335 float getProcessTime() const;
336 float getMaxProcessTime() const;
337
338 const std::shared_ptr<TransportPosition> getTransportPosition() const;
339
340 const PatternList* getNextPatterns() const;
341 const PatternList* getPlayingPatterns() const;
342
343 long long getRealtimeFrame() const;
344
350 static double getLeadLagInTicks();
351
358 long long getLeadLagInFrames( double fTick );
359
360 double getSongSizeInTicks() const;
361
369 void play();
377 void stop();
378
386 void setNextBpm( float fNextBpm );
387 float getNextBpm() const;
388
389 static float getBpmAtColumn( int nColumn );
390
398 void updateSongSize();
399
400 void removePlayingPattern( Pattern* pPattern );
419 void clearNextPatterns();
424 void toggleNextPattern( int nPatternNumber );
431 void flushAndAddNextPattern( int nPatternNumber );
432
434
440 int getEnqueuedNotesNumber() const;
441
442 bool isEndOfSongReached( std::shared_ptr<TransportPosition> pPos ) const;
443
444 void makeTrackPorts( std::shared_ptr<Song> pSong );
445
454 QString toQString( const QString& sPrefix = "", bool bShort = true ) const override;
455
457 friend void Hydrogen::setSong( std::shared_ptr<Song> pSong, bool bRelinking );
459 friend void Hydrogen::removeSong();
468 friend bool CoreActionController::addTempoMarker( int, float );
471 friend bool CoreActionController::locateToTick( long nTick, bool );
476
477 friend class AudioEngineTests;
478 friend class JackAudioDriver;
479private:
480
489
490 inline void processPlayNotes( unsigned long nframes );
491
492 void reset( bool bWithJackBroadcast = true );
493
494 void resetOffsets();
495
507 double coarseGrainTick( double fTick );
508
509 void clearNoteQueues();
512 void clearAudioBuffers( uint32_t nFrames );
518 void updateNoteQueue( unsigned nIntervalLengthInFrames );
519 void processAudio( uint32_t nFrames );
520 long long computeTickInterval( double* fTickStart, double* fTickEnd, unsigned nIntervalLengthInFrames );
521 void updateBpmAndTickSize( std::shared_ptr<TransportPosition> pTransportPosition );
522 void calculateTransportOffsetOnBpmChange( std::shared_ptr<TransportPosition> pTransportPosition );
523
524 void setRealtimeFrame( long long nFrame );
525 void updatePlayingPatternsPos( std::shared_ptr<TransportPosition> pPos );
526
527 void setSong( std::shared_ptr<Song>pNewSong );
528 void removeSong();
529 void setState( State state );
530 void setNextState( State state );
531 State getNextState() const;
532
533 void startPlayback();
534
535 void stopPlayback();
536
537 void locate( const double fTick, bool bWithJackBroadcast = true );
546 void locateToFrame( const long long nFrame );
547 void incrementTransportPosition( uint32_t nFrames );
548 void updateTransportPosition( double fTick, long long nFrame,
549 std::shared_ptr<TransportPosition> pPos );
550 void updateSongTransportPosition( double fTick, long long nFrame,
551 std::shared_ptr<TransportPosition> pPos );
552 void updatePatternTransportPosition( double fTick, long long nFrame,
553 std::shared_ptr<TransportPosition> pPos );
554
559 void handleTempoChange();
560
573
579
585 void handleDriverChange();
586
592
598
599 QString getDriverNames() const;
600
607
608 #if defined(H2CORE_HAVE_LADSPA) || _DOXYGEN_
611 #endif
612
613 //Master peak (left channel)
615
616 //Master peak (right channel)
618
627 std::timed_mutex m_EngineMutex;
628
639
643 std::thread::id m_LockingThread;
644
646 const char* file;
647 unsigned int line;
648 const char* function;
650
654
655 std::shared_ptr<TransportPosition> m_pTransportPosition;
656 std::shared_ptr<TransportPosition> m_pQueuingPosition;
657
660
670
680
682
684 // overload the > operator of Note objects for priority_queue
686 bool operator() (Note* pNote1, Note* pNote2);
687 };
688
689 std::priority_queue<Note*, std::deque<Note*>, compare_pNotes > m_songNoteQueue;
690 std::deque<Note*> m_midiNoteQueue;
691
695 std::shared_ptr<Instrument> m_pMetronomeInstrument;
696
700
704};
705
706#ifdef H2CORE_HAVE_DEBUG
707 #define ASSERT_AUDIO_ENGINE_LOCKED(x) assertAudioEngineLocked( _class_name(), __FUNCTION__, QString( "%1" ).arg( x ) );
708#else
709 #define ASSERT_AUDIO_ENGINE_LOCKED(x)
710#endif
711
727
729
730protected:
734 void assertAudioEngineLocked( const QString& sClass,
735 const char* sFunction,
736 const QString& sMsg ) const;
737
738
739public:
740
746 void setNeedsLock( bool bNeedsLock ) {
747 m_bNeedsLock = bNeedsLock;
748 }
749
751 m_bNeedsLock = false;
752 }
753};
754
755inline void AudioEngine::setMasterPeak_L( float value ) {
756 m_fMasterPeak_L = value;
757}
758
759inline float AudioEngine::getMasterPeak_L() const {
760 return m_fMasterPeak_L;
761}
762
763inline void AudioEngine::setMasterPeak_R( float value ) {
764 m_fMasterPeak_R = value;
765}
766
767inline float AudioEngine::getMasterPeak_R() const {
768 return m_fMasterPeak_R;
769}
770
771inline float AudioEngine::getProcessTime() const {
772 return m_fProcessTime;
773}
774
775inline float AudioEngine::getMaxProcessTime() const {
776 return m_fMaxProcessTime;
777}
778
780 return m_state;
781}
782
787 m_nextState = state;
788}
789
791 return m_pAudioDriver;
792}
793
795 return m_pMidiDriver;
796}
797
801
802inline long long AudioEngine::getRealtimeFrame() const {
803 return m_nRealtimeFrame;
804}
805
806inline void AudioEngine::setRealtimeFrame( long long nFrame ) {
807 m_nRealtimeFrame = nFrame;
808}
809
810inline float AudioEngine::getNextBpm() const {
811 return m_fNextBpm;
812}
813inline const std::shared_ptr<TransportPosition> AudioEngine::getTransportPosition() const {
815}
816inline double AudioEngine::getSongSizeInTicks() const {
817 return m_fSongSizeInTicks;
818}
819inline std::shared_ptr<Instrument> AudioEngine::getMetronomeInstrument() const {
821}
823 return m_songNoteQueue.size();
824}
825};
826
827#endif
int(* audioProcessCallback)(uint32_t, void *)
Definition AudioEngine.h:64
#define H2_OBJECT(name)
Definition Object.h:227
void setNeedsLock(bool bNeedsLock)
The audio processing thread can modify some PatternLists.
void assertAudioEngineLocked(const QString &sClass, const char *sFunction, const QString &sMsg) const
Assert that the AudioEngine lock is held if needed.
int m_nLoopsDone
Indicates how many loops the transport already did when the user presses the Loop button again.
void makeTrackPorts(std::shared_ptr< Song > pSong)
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...
QString getDriverNames() const
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.
static QString StateToQString(const State &state)
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.
friend class AudioEngineTests
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)
void updateTransportPosition(double fTick, long long nFrame, std::shared_ptr< TransportPosition > pPos)
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.
State getNextState() const
AudioOutput * createAudioDriver(const Preferences::AudioDriver &driver)
Create an audio driver using audioEngine_process() as its argument based on the provided choice and c...
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.
friend class JackAudioDriver
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)
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.
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.
void assertLocked(const QString &sClass, const char *sFunction, const QString &sMsg)
Assert that the calling thread is the current holder of the AudioEngine lock.
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:293
void updateSelectedPattern(bool bNeedsLock=true)
Updates the selected pattern to the one recorded note will be inserted to.
Definition Hydrogen.cpp:903
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:101
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)