Skip to content

Commit

Permalink
AudioEngine: make humanization parameters member
Browse files Browse the repository at this point in the history
Previously the standard deviations used to create random Gaussian distributed number for the humanization of velocity, pitch, and timing were just magic numbers. Well, there are actual values are still quite magic but at least there are now reusable static members and documented.
  • Loading branch information
theGreatWhiteShark committed Nov 4, 2022
1 parent 84de931 commit 24a59da
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 24 deletions.
27 changes: 16 additions & 11 deletions src/core/AudioEngine/AudioEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1158,13 +1158,13 @@ void AudioEngine::processPlayNotes( unsigned long nframes )
if ( pSong->getHumanizeVelocityValue() != 0 ) {
pNote->set_velocity( pNote->get_velocity() +
pSong->getHumanizeVelocityValue() *
getGaussian( 0.2 ) );
getGaussian( AudioEngine::fHumanizeVelocitySD ) );
}

float fPitch = pNote->get_pitch() + pNote->get_instrument()->get_pitch_offset();
const float fRandomPitchFactor = pNote->get_instrument()->get_random_pitch_factor();
if ( fRandomPitchFactor != 0. ) {
fPitch += getGaussian( 0.4 ) * fRandomPitchFactor;
if ( pNote->get_instrument()->get_random_pitch_factor() != 0. ) {
fPitch += getGaussian( AudioEngine::fHumanizePitchSD ) *
pNote->get_instrument()->get_random_pitch_factor();
}
pNote->set_pitch( fPitch );

Expand Down Expand Up @@ -2381,11 +2381,10 @@ int AudioEngine::updateNoteQueue( unsigned nIntervalLengthInFrames )
* random variable.
*/
if ( pSong->getHumanizeTimeValue() != 0 ) {
nOffset += ( int )(
getGaussian( 0.3 )
* pSong->getHumanizeTimeValue()
* AudioEngine::nMaxTimeHumanize
);
nOffset += (int) (
getGaussian( AudioEngine::fHumanizeTimingSD ) *
pSong->getHumanizeTimeValue() *
AudioEngine::nMaxTimeHumanize );
}

// Lead or Lag
Expand Down Expand Up @@ -2592,7 +2591,10 @@ QString AudioEngine::toQString( const QString& sPrefix, bool bShort ) const {
sOutput.append( nn->toQString( sPrefix + s, bShort ) );
}
sOutput.append( QString( "]\n%1%2m_pMetronomeInstrument: %3\n" ).arg( sPrefix ).arg( s ).arg( m_pMetronomeInstrument->toQString( sPrefix + s, bShort ) ) )
.append( QString( "%1%2nMaxTimeHumanize: %3\n" ).arg( sPrefix ).arg( s ).arg( AudioEngine::nMaxTimeHumanize ) );
.append( QString( "%1%2nMaxTimeHumanize: %3\n" ).arg( sPrefix ).arg( s ).arg( AudioEngine::nMaxTimeHumanize ) )
.append( QString( "%1%2fHumanizeVelocitySD: %3\n" ).arg( sPrefix ).arg( s ).arg( AudioEngine::fHumanizeVelocitySD ) )
.append( QString( "%1%2fHumanizePitchSD: %3\n" ).arg( sPrefix ).arg( s ).arg( AudioEngine::fHumanizePitchSD ) )
.append( QString( "%1%2fHumanizeTimingSD: %3\n" ).arg( sPrefix ).arg( s ).arg( AudioEngine::fHumanizeTimingSD ) );

}
else {
Expand Down Expand Up @@ -2647,7 +2649,10 @@ QString AudioEngine::toQString( const QString& sPrefix, bool bShort ) const {
sOutput.append( nn->toQString( sPrefix + s, bShort ) );
}
sOutput.append( QString( "], m_pMetronomeInstrument: id = %1" ).arg( m_pMetronomeInstrument->get_id() ) )
.append( QString( ", nMaxTimeHumanize: id %1" ).arg( AudioEngine::nMaxTimeHumanize ) );
.append( QString( ", nMaxTimeHumanize: id %1" ).arg( AudioEngine::nMaxTimeHumanize ) )
.append( QString( ", fHumanizeVelocitySD: id %1" ).arg( AudioEngine::fHumanizeVelocitySD ) )
.append( QString( ", fHumanizePitchSD: id %1" ).arg( AudioEngine::fHumanizePitchSD ) )
.append( QString( ", fHumanizeTimingSD: id %1" ).arg( AudioEngine::fHumanizeTimingSD ) );
}

return sOutput;
Expand Down
30 changes: 30 additions & 0 deletions src/core/AudioEngine/AudioEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,36 @@ class AudioEngine : public H2Core::Object<AudioEngine>
Testing = 6
};

/**
* Maximum value the standard deviation of the Gaussian
* distribution the random velocity contribution will be drawn
* from can take.
*
* The actual standard deviation used during processing is this
* value multiplied with #Song::m_fHumanizeVelocityValue.
*/
static constexpr float fHumanizeVelocitySD = 0.2;
/**
* Maximum value the standard deviation of the Gaussian
* distribution the random pitch contribution will be drawn from
* can take.
*
* The actual standard deviation used during processing is this
* value multiplied with #Instrument::__random_pitch_factor of the
* instrument associated with the particular #Note.
*/
static constexpr float fHumanizePitchSD = 0.4;
/**
* Maximum value the standard deviation of the Gaussian
* distribution the random pitch contribution will be drawn from
* can take.
*
* The actual standard deviation used during processing is this
* value multiplied with #Instrument::__random_pitch_factor of the
* instrument associated with the particular #Note.
*/
static constexpr float fHumanizeTimingSD = 0.3;

AudioEngine();

~AudioEngine();
Expand Down
18 changes: 6 additions & 12 deletions src/core/AudioEngine/AudioEngineTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1430,24 +1430,18 @@ void AudioEngineTests::testHumanization() {
// multiplied with the humanization value set via the
// GUI. With the latter ranging from 0 to 1 the factor
// represent the maximum standard deviation available.
checkDeviation( &deviationsVelocity, 0.2 * fValue, "velocity" );
checkDeviation( &deviationsVelocity,
AudioEngine::fHumanizeVelocitySD * fValue, "velocity" );
checkDeviation( &deviationsTiming,
0.3 * AudioEngine::nMaxTimeHumanize * fValue, "timing" );
checkDeviation( &deviationsPitch, 0.4 * fValue, "pitch" );
AudioEngine::fHumanizeTimingSD *
AudioEngine::nMaxTimeHumanize * fValue, "timing" );
checkDeviation( &deviationsPitch,
AudioEngine::fHumanizePitchSD * fValue, "pitch" );
};

setHumanization( 0.2 );
std::vector<std::shared_ptr<Note>> notesHumanizedWeak;
getNotes( &notesHumanizedWeak );

// qDebug() << "reference";
// for ( auto note : notesReference ) {
// qDebug() << note->toQString();
// }
// qDebug() << "custom";
// for ( auto note : notesCustomized ) {
// qDebug() << note->toQString();
// }
checkHumanization( 0.2, &notesHumanizedWeak );

setHumanization( 0.8 );
Expand Down
8 changes: 7 additions & 1 deletion src/core/Basics/Instrument.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,13 @@ class Instrument : public H2Core::Object<Instrument>
bool __filter_active; ///< is filter active?
float __filter_cutoff; ///< filter cutoff (0..1)
float __filter_resonance; ///< filter resonant frequency (0..1)
float __random_pitch_factor; ///< random pitch factor
/**
* Factor to scale the random contribution when humanizing pitch
* between 0 and #AudioEngine::fHumanizePitchSD.
*
* Supported range [0,1].
*/
float __random_pitch_factor;
float __pitch_offset; ///< instrument main pitch offset
int __midi_out_note; ///< midi out note
int __midi_out_channel; ///< midi out channel
Expand Down
12 changes: 12 additions & 0 deletions src/core/Basics/Song.h
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,19 @@ class Song : public H2Core::Object<Song>, public std::enable_shared_from_this<So
*/
LoopMode m_loopMode;
PatternMode m_patternMode;
/**
* Factor to scale the random contribution when humanizing
* timing between 0 and #AudioEngine::fHumanizeTimingSD.
*
* Supported range [0,1].
*/
float m_fHumanizeTimeValue;
/**
* Factor to scale the random contribution when humanizing
* velocity between 0 and #AudioEngine::fHumanizeVelocitySD.
*
* Supported range [0,1].
*/
float m_fHumanizeVelocityValue;
float m_fSwingFactor;
bool m_bIsModified;
Expand Down

0 comments on commit 24a59da

Please sign in to comment.