43const char*
Note::__key_str[] = {
"C",
"Cs",
"D",
"Ef",
"E",
"F",
"Fs",
"G",
"Af",
"A",
"Bf",
"B" };
45Note::Note( std::shared_ptr<Instrument> pInstrument,
int nPosition,
float fVelocity,
float fPan,
int nLength,
float fPitch )
72 if ( pInstrument !=
nullptr ) {
73 __adsr = pInstrument->copy_adsr();
76 for (
const auto& pCompo : *pInstrument->get_components() ) {
77 std::shared_ptr<SelectedLayerInfo> pSampleInfo = std::make_shared<SelectedLayerInfo>();
78 pSampleInfo->nSelectedLayer = -1;
79 pSampleInfo->fSamplePosition = 0;
80 pSampleInfo->nNoteLength = -1;
125 std::shared_ptr<SelectedLayerInfo> pSampleInfo = std::make_shared<SelectedLayerInfo>();
126 pSampleInfo->nSelectedLayer = mm.second->nSelectedLayer;
127 pSampleInfo->fSamplePosition = mm.second->fSamplePosition;
128 pSampleInfo->nNoteLength = mm.second->nNoteLength;
130 __layers_selected[ mm.first ] = pSampleInfo;
140 return std::clamp( fValue, fMin, fMax );
170 if ( pInstrumentList ==
nullptr ) {
171 assert( pInstrumentList );
172 ERRORLOG(
"Invalid instrument list" );
177 if ( pInstr ==
nullptr ) {
178 ERRORLOG( QString(
"Instrument with ID [%1] not found. Using empty instrument." )
184 __adsr = pInstr->copy_adsr();
186 for (
const auto& ppCompo : *pInstr->get_components() ) {
187 std::shared_ptr<SelectedLayerInfo> sampleInfo = std::make_shared<SelectedLayerInfo>();
188 sampleInfo->nSelectedLayer = -1;
189 sampleInfo->fSamplePosition = 0;
190 sampleInfo->nNoteLength = -1;
204 int l = str.length();
205 QString s_key = str.left( l-1 );
206 QString s_oct = str.mid( l-1, l );
207 if ( s_key.endsWith(
"-" ) ) {
208 s_key.replace(
"-",
"" );
209 s_oct.insert( 0,
"-" );
225 if ( ll.second->fSamplePosition > 0 ) {
236 auto pAudioEngine = pHydrogen->getAudioEngine();
238 double fTickMismatch;
251 if ( pHydrogen->isTimelineEnabled() ) {
264 std::shared_ptr<Sample> pSample;
267 ERRORLOG(
"Sample does not hold an instrument" );
271 auto pInstrCompo =
__instrument->get_component( nComponentID );
272 if ( pInstrCompo ==
nullptr ) {
273 ERRORLOG( QString(
"Unable to retrieve component [%1] of instrument [%2]" )
279 if ( pSelectedLayer ==
nullptr ) {
280 WARNINGLOG( QString(
"No SelectedLayer for component ID [%1] of instrument [%2]" )
285 if ( pSelectedLayer->nSelectedLayer != -1 ||
286 nSelectedLayer != -1 ) {
291 int nLayer = pSelectedLayer->nSelectedLayer != -1 ?
292 pSelectedLayer->nSelectedLayer : nSelectedLayer;
294 if ( pSelectedLayer->nSelectedLayer != -1 &&
295 nSelectedLayer != -1 &&
296 pSelectedLayer->nSelectedLayer != nSelectedLayer ) {
297 WARNINGLOG( QString(
"Previously selected layer [%1] and requested layer [%2] differ. The previous one will be used." )
298 .arg( pSelectedLayer->nSelectedLayer )
299 .arg( nSelectedLayer ) );
302 auto pLayer = pInstrCompo->get_layer( nLayer );
303 if ( pLayer ==
nullptr ) {
304 ERRORLOG( QString(
"Unable to retrieve layer [%1] selected for component [%2] of instrument [%3]" )
310 pSample = pLayer->get_sample();
314 std::vector<int> possibleLayersVector;
319 auto pLayer = pInstrCompo->get_layer( nLayer );
320 if ( pLayer ==
nullptr ) {
324 if ( (
__velocity >= pLayer->get_start_velocity() ) &&
327 possibleLayersVector.push_back( nLayer );
331 fRoundRobinID = pLayer->get_start_velocity();
345 if ( possibleLayersVector.size() == 0 ){
346 float shortestDistance = 1.0f;
347 int nearestLayer = -1;
349 auto pLayer = pInstrCompo->get_layer( nLayer );
350 if ( pLayer ==
nullptr ){
354 if ( std::min( abs( pLayer->get_start_velocity() -
__velocity ),
355 abs( pLayer->get_start_velocity() -
__velocity ) ) <
358 std::min( abs( pLayer->get_start_velocity() -
__velocity ),
359 abs( pLayer->get_start_velocity() -
__velocity ) );
360 nearestLayer = nLayer;
364 if ( nearestLayer > -1 ){
366 possibleLayersVector.push_back( nearestLayer );
369 pInstrCompo->get_layer( nearestLayer )->get_start_velocity();
377 if ( possibleLayersVector.size() > 0 ) {
382 nLayerPicked = possibleLayersVector[ 0 ];
386 nLayerPicked = possibleLayersVector[ rand() %
387 possibleLayersVector.size() ];
391 fRoundRobinID =
__instrument->get_id() * 10 + fRoundRobinID;
392 int nIndex = pSong->getLatestRoundRobin( fRoundRobinID ) + 1;
393 if ( nIndex >= possibleLayersVector.size() ) {
397 pSong->setLatestRoundRobin( fRoundRobinID, nIndex );
398 nLayerPicked = possibleLayersVector[ nIndex ];
403 ERRORLOG( QString(
"Unknown selection algorithm [%1] for instrument [%2]" )
409 pSelectedLayer->nSelectedLayer = nLayerPicked;
410 auto pLayer = pInstrCompo->get_layer( nLayerPicked );
411 pSample = pLayer->get_sample();
414 ERRORLOG(
"No samples found during random layer selection. This is a bug and shoul dn't happen!" );
436 if ( pSong !=
nullptr ) {
437 const float fRandomVelocityFactor = pSong->getHumanizeVelocityValue();
438 if ( fRandomVelocityFactor != 0 ) {
443 const float fRandomTimeFactor = pSong->getHumanizeTimeValue();
444 if ( fRandomTimeFactor != 0 ) {
452 const float fRandomPitchFactor =
__instrument->get_random_pitch_factor();
453 if ( fRandomPitchFactor != 0 ) {
462 if ( pSong !=
nullptr && pSong->getSwingFactor() > 0 ) {
476 double fTickMismatch;
482 pSong->getSwingFactor() );
502 bool bFound, bFound2;
503 float fPan = node->
read_float(
"pan", 0.f, &bFound,
true,
false,
true );
507 float fPanL = node->
read_float(
"pan_L", 1.f, &bFound,
false,
false, bSilent );
508 float fPanR = node->
read_float(
"pan_R", 1.f, &bFound2,
false,
false, bSilent );
509 if ( bFound && bFound2 ) {
512 WARNINGLOG( QString(
"Neither `pan` nor `pan_L` and `pan_R` were found. Falling back to `pan = 0`" ) );
518 node->
read_int(
"position", 0,
false,
false, bSilent ),
519 node->
read_float(
"velocity", 0.8f,
false,
false, bSilent ),
521 node->
read_int(
"length", -1,
true,
false, bSilent ),
522 node->
read_float(
"pitch", 0.0f,
false,
false, bSilent )
538 sOutput = QString(
"%1[Note]\n" ).arg( sPrefix )
539 .append( QString(
"%1%2instrument_id: %3\n" ).arg( sPrefix ).arg( s ).arg(
__instrument_id ) )
540 .append( QString(
"%1%2specific_compo_id: %3\n" ).arg( sPrefix ).arg( s ).arg(
__specific_compo_id ) )
541 .append( QString(
"%1%2position: %3\n" ).arg( sPrefix ).arg( s ).arg(
__position ) )
542 .append( QString(
"%1%2m_nNoteStart: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_nNoteStart ) )
543 .append( QString(
"%1%2m_fUsedTickSize: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fUsedTickSize ) )
544 .append( QString(
"%1%2velocity: %3\n" ).arg( sPrefix ).arg( s ).arg(
__velocity ) )
545 .append( QString(
"%1%2pan: %3\n" ).arg( sPrefix ).arg( s ).arg(
m_fPan ) )
546 .append( QString(
"%1%2length: %3\n" ).arg( sPrefix ).arg( s ).arg(
__length ) )
547 .append( QString(
"%1%2pitch: %3\n" ).arg( sPrefix ).arg( s ).arg(
__pitch ) )
548 .append( QString(
"%1%2key: %3\n" ).arg( sPrefix ).arg( s ).arg(
__key ) )
549 .append( QString(
"%1%2octave: %3\n" ).arg( sPrefix ).arg( s ).arg(
__octave ) );
550 if (
__adsr !=
nullptr ) {
551 sOutput.append( QString(
"%1" )
552 .arg(
__adsr->toQString( sPrefix + s, bShort ) ) );
554 sOutput.append( QString(
"%1%2adsr: nullptr\n" ).arg( sPrefix ).arg( s ) );
557 sOutput.append( QString(
"%1%2lead_lag: %3\n" ).arg( sPrefix ).arg( s ).arg(
__lead_lag ) )
558 .append( QString(
"%1%2cut_off: %3\n" ).arg( sPrefix ).arg( s ).arg(
__cut_off ) )
559 .append( QString(
"%1%2resonance: %3\n" ).arg( sPrefix ).arg( s ).arg(
__resonance ) )
560 .append( QString(
"%1%2humanize_delay: %3\n" ).arg( sPrefix ).arg( s ).arg(
__humanize_delay ) )
561 .append( QString(
"%1%2key: %3\n" ).arg( sPrefix ).arg( s ).arg(
__key ) )
562 .append( QString(
"%1%2bpfb_l: %3\n" ).arg( sPrefix ).arg( s ).arg(
__bpfb_l ) )
563 .append( QString(
"%1%2bpfb_r: %3\n" ).arg( sPrefix ).arg( s ).arg(
__bpfb_r ) )
564 .append( QString(
"%1%2lpfb_l: %3\n" ).arg( sPrefix ).arg( s ).arg(
__lpfb_l ) )
565 .append( QString(
"%1%2lpfb_r: %3\n" ).arg( sPrefix ).arg( s ).arg(
__lpfb_r ) )
566 .append( QString(
"%1%2pattern_idx: %3\n" ).arg( sPrefix ).arg( s ).arg(
__pattern_idx ) )
567 .append( QString(
"%1%2midi_msg: %3\n" ).arg( sPrefix ).arg( s ).arg(
__midi_msg ) )
568 .append( QString(
"%1%2note_off: %3\n" ).arg( sPrefix ).arg( s ).arg(
__note_off ) )
569 .append( QString(
"%1%2just_recorded: %3\n" ).arg( sPrefix ).arg( s ).arg(
__just_recorded ) )
570 .append( QString(
"%1%2probability: %3\n" ).arg( sPrefix ).arg( s ).arg(
__probability ) );
572 sOutput.append( QString(
"%1" ).arg(
__instrument->toQString( sPrefix + s, bShort ) ) );
574 sOutput.append( QString(
"%1%2instrument: nullptr\n" ).arg( sPrefix ).arg( s ) );
576 sOutput.append( QString(
"%1%2layers_selected:\n" )
577 .arg( sPrefix ).arg( s ) );
579 if ( ll.second !=
nullptr ) {
580 sOutput.append( QString(
"%1%2[component: %3, selected layer: %4, sample position: %5, note length: %6]\n" )
581 .arg( sPrefix ).arg( s + s )
583 .arg( ll.second->nSelectedLayer )
584 .arg( ll.second->fSamplePosition )
585 .arg( ll.second->nNoteLength ) );
587 sOutput.append( QString(
"%1%2[component: %3, selected layer info: nullptr]\n" )
588 .arg( sPrefix ).arg( s + s )
594 sOutput = QString(
"[Note]" )
597 .append( QString(
", position: %1" ).arg(
__position ) )
598 .append( QString(
", m_nNoteStart: %1" ).arg(
m_nNoteStart ) )
600 .append( QString(
", velocity: %1" ).arg(
__velocity ) )
601 .append( QString(
", pan: %1" ).arg(
m_fPan ) )
602 .append( QString(
", length: %1" ).arg(
__length ) )
603 .append( QString(
", pitch: %1" ).arg(
__pitch ) )
604 .append( QString(
", key: %1" ).arg(
__key ) )
605 .append( QString(
", octave: %1" ).arg(
__octave ) );
606 if (
__adsr !=
nullptr ) {
607 sOutput.append( QString(
", [%1" )
608 .arg(
__adsr->toQString( sPrefix + s, bShort )
609 .replace(
"\n",
"]" ) ) );
611 sOutput.append(
", adsr: nullptr" );
614 sOutput.append( QString(
", lead_lag: %1" ).arg(
__lead_lag ) )
615 .append( QString(
", cut_off: %1" ).arg(
__cut_off ) )
616 .append( QString(
", resonance: %1" ).arg(
__resonance ) )
618 .append( QString(
", key: %1" ).arg(
__key ) )
619 .append( QString(
", bpfb_l: %1" ).arg(
__bpfb_l ) )
620 .append( QString(
", bpfb_r: %1" ).arg(
__bpfb_r ) )
621 .append( QString(
", lpfb_l: %1" ).arg(
__lpfb_l ) )
622 .append( QString(
", lpfb_r: %1" ).arg(
__lpfb_r ) )
623 .append( QString(
", pattern_idx: %1" ).arg(
__pattern_idx ) )
624 .append( QString(
", midi_msg: %1" ).arg(
__midi_msg ) )
625 .append( QString(
", note_off: %1" ).arg(
__note_off ) )
627 .append( QString(
", probability: %1" ).arg(
__probability ) );
629 sOutput.append( QString(
", instrument: %1" ).arg(
__instrument->get_name() ) );
631 sOutput.append( QString(
", instrument: nullptr" ) );
633 sOutput.append( QString(
", layers_selected: " ) );
635 if ( ll.second !=
nullptr ) {
636 sOutput.append( QString(
"[component: %1, selected layer: %2, sample position: %3, note length: %4] " )
638 .arg( ll.second->nSelectedLayer )
639 .arg( ll.second->fSamplePosition )
640 .arg( ll.second->nNoteLength ) );
642 sOutput.append( QString(
"[component: %1, selected layer info: nullptr]" )
691 ERRORLOG(QString(
"Unknown Key value [%1]" ).arg( key ) );
static constexpr float fHumanizePitchSD
Maximum value the standard deviation of the Gaussian distribution the random pitch contribution will ...
static constexpr float fHumanizeTimingSD
Maximum value the standard deviation of the Gaussian distribution the random pitch contribution will ...
static constexpr int nMaxTimeHumanize
Maximum time (in frames) a note's position can be off due to the humanization (lead-lag).
static constexpr float fHumanizeVelocitySD
Maximum value the standard deviation of the Gaussian distribution the random velocity contribution wi...
static QString sPrintIndention
String used to format the debugging string output of some core classes.
std::shared_ptr< Song > getSong() const
Get the current song.
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
static int getMaxLayers()
int get_position() const
__position accessor
int __humanize_delay
frequency [0;1]
float m_fUsedTickSize
TransportPosition::m_fTickSize used to calculate m_nNoteStart.
std::shared_ptr< SelectedLayerInfo > get_layer_selected(int CompoID)
float get_lpfb_r() const
__lpfb_r accessor
void swing()
Add swing contribution to __humanize_delay.
bool isPartiallyRendered() const
int __pattern_idx
index of the pattern holding this note for undo actions
float get_bpfb_r() const
__bpfb_r accessor
std::shared_ptr< Instrument > __instrument
the instrument to be played by this note
void set_lead_lag(float value)
__lead_lag setter
float get_resonance() const
__resonance accessor
static QString KeyToQString(Key key)
float m_fPan
pan of the note, [-1;1] from
float __lpfb_l
left low pass filter buffer
void set_humanize_delay(int value)
__humanize_delay setter
void set_key_octave(const QString &str)
parse str and set __key and __octave
int __position
note position in
void map_instrument(std::shared_ptr< InstrumentList > instruments)
find the corresponding instrument and point to it, or an empty instrument
static Note * load_from(XMLNode *node, std::shared_ptr< InstrumentList > instruments, bool bSilent=false)
load a note from an XMLNode
float __resonance
filter resonant
Octave get_octave()
__octave accessor
void set_probability(float value)
int get_humanize_delay() const
__humanize_delay accessor
float __lead_lag
lead or lag offset of the note
std::shared_ptr< Instrument > get_instrument()
__instrument accessor
float get_bpfb_l() const
__bpfb_l accessor
int get_midi_msg() const
__midi_msg accessor
float get_total_pitch() const
bool __just_recorded
used in record+delete
float get_lead_lag() const
__lead_lag accessor
float getUsedTickSize() const
void save_to(XMLNode *node)
float get_pitch() const
__pitch accessor
void humanize()
Add random contributions to __pitch, __humanize_delay, and __velocity.
int __length
left to right, as requested by Sampler PanLaws
std::shared_ptr< Sample > getSample(int nComponentID, int nSelectedLayer=-1)
Returns the sample associated with the note for a specific InstrumentComponent nComponentID.
int get_length() const
__length accessor
void set_instrument_id(int value)
__instrument_id setter
float __pitch
the frequency of the note
float __velocity
ticks inside the pattern
int get_pattern_idx() const
__pattern_idx accessor
float __probability
note probability
QString key_to_string()
return a string representation of key-octave
bool get_just_recorded() const
__just_recorded accessor
float get_velocity() const
__velocity accessor
bool get_note_off() const
__note_off accessor
void computeNoteStart()
Calculates the m_nNoteStart in frames corresponding to the __position in ticks and storing the used t...
void setPan(float val)
set pan of the note.
float __lpfb_r
right low pass filter buffer
void set_velocity(float value)
__velocity setter
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
float __cut_off
filter cutoff [0;1]
std::map< int, std::shared_ptr< SelectedLayerInfo > > __layers_selected
long long getNoteStart() const
std::shared_ptr< ADSR > __adsr
attack decay sustain release
void set_note_off(bool value)
__note_off setter
float get_cut_off() const
__cut_off accessor
bool __note_off
note type on|off
long long m_nNoteStart
from __key an __octave
Key get_key()
__key accessor
float __bpfb_l
left band pass filter buffer
Key __key
the key, [0;11]==[C;B]
float get_probability() const
Octave __octave
the octave [-3;3]
float get_lpfb_l() const
__lpfb_l accessor
Note(std::shared_ptr< Instrument > pInstrument, int nPosition=0, float fVelocity=0.8, float fPan=0.0, int nLength=-1, float fPitch=0.0)
constructor
float getPan() const
get pan of the note.
float __bpfb_r
right band pass filter buffer
int __instrument_id
the id of the instrument played by this note
int __specific_compo_id
play a specific component, -1 if playing all
static const char * __key_str[]
used to build QString
static float getGaussian(float fStandardDeviation)
Draws an uncorrelated random value from a Gaussian distribution of mean 0 and fStandardDeviation.
static float getRatioPan(float fPan_L, float fPan_R)
This function is used to load old version files (v<=1.1).
static long long computeFrameFromTick(double fTick, double *fTickMismatch, int nSampleRate=0)
Calculates frame equivalent of fTick.
XMLNode is a subclass of QDomNode with read and write values methods.
int read_int(const QString &node, int default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads an integer stored into a child node
bool read_bool(const QString &node, bool default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads a boolean stored into a child node
QString read_string(const QString &node, const QString &default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads a string stored into a child node
float read_float(const QString &node, float default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads a float stored into a child node
void write_float(const QString &node, const float value)
write a float into a child node
void write_string(const QString &node, const QString &value)
write a string into a child node
void write_bool(const QString &node, const bool value)
write a boolean into a child node
void write_int(const QString &node, const int value)
write an integer into a child node
#define MAX_NOTES
Maximum number of notes.
static float check_boundary(float fValue, float fMin, float fMax)