hydrogen 1.2.6
Note.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
23#include <core/Basics/Note.h>
24
25#include <cassert>
26
27#include <core/Helpers/Random.h>
28#include <core/Helpers/Xml.h>
31#include <core/Basics/Adsr.h>
36#include <core/Basics/Song.h>
37#include <core/Hydrogen.h>
39
40namespace H2Core
41{
42
43const char* Note::__key_str[] = { "C", "Cs", "D", "Ef", "E", "F", "Fs", "G", "Af", "A", "Bf", "B" };
44
45Note::Note( std::shared_ptr<Instrument> pInstrument, int nPosition, float fVelocity, float fPan, int nLength, float fPitch )
46 : __instrument( pInstrument ),
47 __instrument_id( 0 ),
49 __position( nPosition ),
50 __velocity( fVelocity ),
51 __length( nLength ),
52 __pitch( fPitch ),
53 __key( C ),
54 __octave( P8 ),
55 __adsr( nullptr ),
56 __lead_lag( 0.0 ),
57 __cut_off( 1.0 ),
58 __resonance( 0.0 ),
60 __bpfb_l( 0.0 ),
61 __bpfb_r( 0.0 ),
62 __lpfb_l( 0.0 ),
63 __lpfb_r( 0.0 ),
64 __pattern_idx( 0 ),
65 __midi_msg( -1 ),
66 __note_off( false ),
67 __just_recorded( false ),
68 __probability( 1.0f ),
69 m_nNoteStart( 0 ),
70 m_fUsedTickSize( std::nan("") )
71{
72 if ( pInstrument != nullptr ) {
73 __adsr = pInstrument->copy_adsr();
74 __instrument_id = pInstrument->get_id();
75
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;
81
82 __layers_selected[ pCompo->get_drumkit_componentID() ] = pSampleInfo;
83 }
84 }
85
86 setPan( fPan ); // this checks the boundaries
87}
88
89Note::Note( Note* other, std::shared_ptr<Instrument> instrument )
90 : Object( *other ),
91 __instrument( other->get_instrument() ),
92 __instrument_id( 0 ),
94 __position( other->get_position() ),
95 __velocity( other->get_velocity() ),
96 m_fPan( other->getPan() ),
97 __length( other->get_length() ),
98 __pitch( other->get_pitch() ),
99 __key( other->get_key() ),
100 __octave( other->get_octave() ),
101 __adsr( nullptr ),
102 __lead_lag( other->get_lead_lag() ),
103 __cut_off( other->get_cut_off() ),
104 __resonance( other->get_resonance() ),
106 __bpfb_l( other->get_bpfb_l() ),
107 __bpfb_r( other->get_bpfb_r() ),
108 __lpfb_l( other->get_lpfb_l() ),
109 __lpfb_r( other->get_lpfb_r() ),
110 __pattern_idx( other->get_pattern_idx() ),
111 __midi_msg( other->get_midi_msg() ),
112 __note_off( other->get_note_off() ),
114 __probability( other->get_probability() ),
115 m_nNoteStart( other->getNoteStart() ),
117{
118 if ( instrument != nullptr ) __instrument = instrument;
119 if ( __instrument != nullptr ) {
120 __adsr = __instrument->copy_adsr();
121 __instrument_id = __instrument->get_id();
122 }
123
124 for ( const auto& mm : other->__layers_selected ) {
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;
129
130 __layers_selected[ mm.first ] = pSampleInfo;
131 }
132}
133
135{
136}
137
138static inline float check_boundary( float fValue, float fMin, float fMax )
139{
140 return std::clamp( fValue, fMin, fMax );
141}
142
143void Note::set_velocity( float velocity )
144{
146}
147
148void Note::set_lead_lag( float lead_lag )
149{
151}
152
153void Note::setPan( float val ) {
154 m_fPan = check_boundary( val, -1.0f, 1.0f );
155}
156
157void Note::set_humanize_delay( int nValue )
158{
159 // We do not perform bound checks with
160 // AudioEngine::nMaxTimeHumanize in here as different contribution
161 // could push the value first beyond and then within the bounds
162 // again. The clamping will be done in computeNoteStart() instead.
163 if ( nValue != __humanize_delay ) {
164 __humanize_delay = nValue;
165 }
166}
167
168void Note::map_instrument( std::shared_ptr<InstrumentList> pInstrumentList )
169{
170 if ( pInstrumentList == nullptr ) {
171 assert( pInstrumentList );
172 ERRORLOG( "Invalid instrument list" );
173 return;
174 }
175
176 auto pInstr = pInstrumentList->find( __instrument_id );
177 if ( pInstr == nullptr ) {
178 ERRORLOG( QString( "Instrument with ID [%1] not found. Using empty instrument." )
179 .arg( __instrument_id ) );
180 __instrument = std::make_shared<Instrument>();
181 }
182 else {
183 __instrument = pInstr;
184 __adsr = pInstr->copy_adsr();
185
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;
191
192 __layers_selected[ ppCompo->get_drumkit_componentID() ] = sampleInfo;
193 }
194 }
195}
196
198{
199 return QString( "%1%2" ).arg( __key_str[__key] ).arg( __octave );
200}
201
202void Note::set_key_octave( const QString& str )
203{
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, "-" );
210 }
211 __octave = ( Octave )s_oct.toInt();
212 for( int i=KEY_MIN; i<=KEY_MAX; i++ ) {
213 if( __key_str[i]==s_key ) {
214 __key = ( Key )i;
215 return;
216 }
217 }
218 ___ERRORLOG( "Unhandled key: " + s_key );
219}
220
222 bool bRes = false;
223
224 for ( auto ll : __layers_selected ) {
225 if ( ll.second->fSamplePosition > 0 ) {
226 bRes = true;
227 break;
228 }
229 }
230
231 return bRes;
232}
233
235 auto pHydrogen = Hydrogen::get_instance();
236 auto pAudioEngine = pHydrogen->getAudioEngine();
237
238 double fTickMismatch;
241
242 m_nNoteStart += std::clamp( __humanize_delay,
245
246 // No note can start before the beginning of the song.
247 if ( m_nNoteStart < 0 ) {
248 m_nNoteStart = 0;
249 }
250
251 if ( pHydrogen->isTimelineEnabled() ) {
252 m_fUsedTickSize = -1;
253 } else {
254 // This is used for triggering recalculation in case the tempo
255 // changes where manually applied by the user. They are not
256 // dependent on a particular position of the transport (as
257 // Timeline is not activated).
258 m_fUsedTickSize = pAudioEngine->getTransportPosition()->getTickSize();
259 }
260}
261
262std::shared_ptr<Sample> Note::getSample( int nComponentID, int nSelectedLayer ) {
263
264 std::shared_ptr<Sample> pSample;
265
266 if ( __instrument == nullptr ) {
267 ERRORLOG( "Sample does not hold an instrument" );
268 return nullptr;
269 }
270
271 auto pInstrCompo = __instrument->get_component( nComponentID );
272 if ( pInstrCompo == nullptr ) {
273 ERRORLOG( QString( "Unable to retrieve component [%1] of instrument [%2]" )
274 .arg( nComponentID ).arg( __instrument->get_name() ) );
275 return nullptr;
276 }
277
278 auto pSelectedLayer = get_layer_selected( nComponentID );
279 if ( pSelectedLayer == nullptr ) {
280 WARNINGLOG( QString( "No SelectedLayer for component ID [%1] of instrument [%2]" )
281 .arg( nComponentID ).arg( __instrument->get_name() ) );
282 return nullptr;
283 }
284
285 if ( pSelectedLayer->nSelectedLayer != -1 ||
286 nSelectedLayer != -1 ) {
287 // This function was already called for this note and a
288 // specific layer the sample will be taken from was already
289 // selected or it is provided as an input argument.
290
291 int nLayer = pSelectedLayer->nSelectedLayer != -1 ?
292 pSelectedLayer->nSelectedLayer : nSelectedLayer;
293
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 ) );
300 }
301
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]" )
305 .arg( nLayer )
306 .arg( nComponentID ).arg( __instrument->get_name() ) );
307 return nullptr;
308 }
309
310 pSample = pLayer->get_sample();
311
312 } else {
313 // Select an instrument layer.
314 std::vector<int> possibleLayersVector;
315 float fRoundRobinID;
316 auto pSong = Hydrogen::get_instance()->getSong();
317
318 for ( unsigned nLayer = 0; nLayer < InstrumentComponent::getMaxLayers(); ++nLayer ) {
319 auto pLayer = pInstrCompo->get_layer( nLayer );
320 if ( pLayer == nullptr ) {
321 continue;
322 }
323
324 if ( ( __velocity >= pLayer->get_start_velocity() ) &&
325 ( __velocity <= pLayer->get_end_velocity() ) ) {
326
327 possibleLayersVector.push_back( nLayer );
328 if ( __instrument->sample_selection_alg() == Instrument::VELOCITY ) {
329 break;
330 } else if ( __instrument->sample_selection_alg() == Instrument::ROUND_ROBIN ) {
331 fRoundRobinID = pLayer->get_start_velocity();
332 }
333 }
334 }
335
336 // In some instruments the start and end velocities of a layer are not
337 // set perfectly giving rise to some 'holes'. Occasionally, the velocity
338 // of a note will fall into it. We have to take care of that by
339 // searching for the nearest sample and play this one instead.
340 //
341 // Apart from that, when having multiple components but not an
342 // associated sample for all of them in all instruments (this is
343 // especially likely to happen with kits created in Hydrogen version >=
344 // 2.0), we might not find a sample in here.
345 if ( possibleLayersVector.size() == 0 ){
346 float shortestDistance = 1.0f;
347 int nearestLayer = -1;
348 for ( unsigned nLayer = 0; nLayer < InstrumentComponent::getMaxLayers(); ++nLayer ){
349 auto pLayer = pInstrCompo->get_layer( nLayer );
350 if ( pLayer == nullptr ){
351 continue;
352 }
353
354 if ( std::min( abs( pLayer->get_start_velocity() - __velocity ),
355 abs( pLayer->get_start_velocity() - __velocity ) ) <
356 shortestDistance ){
357 shortestDistance =
358 std::min( abs( pLayer->get_start_velocity() - __velocity ),
359 abs( pLayer->get_start_velocity() - __velocity ) );
360 nearestLayer = nLayer;
361 }
362 }
363
364 if ( nearestLayer > -1 ){
365 // velocity fell into a hole.
366 possibleLayersVector.push_back( nearestLayer );
367 if ( __instrument->sample_selection_alg() == Instrument::ROUND_ROBIN ) {
368 fRoundRobinID =
369 pInstrCompo->get_layer( nearestLayer )->get_start_velocity();
370 }
371 } else {
372 // there is no sample.
373 return nullptr;
374 }
375 }
376
377 if ( possibleLayersVector.size() > 0 ) {
378
379 int nLayerPicked;
380 switch ( __instrument->sample_selection_alg() ) {
382 nLayerPicked = possibleLayersVector[ 0 ];
383 break;
384
386 nLayerPicked = possibleLayersVector[ rand() %
387 possibleLayersVector.size() ];
388 break;
389
391 fRoundRobinID = __instrument->get_id() * 10 + fRoundRobinID;
392 int nIndex = pSong->getLatestRoundRobin( fRoundRobinID ) + 1;
393 if ( nIndex >= possibleLayersVector.size() ) {
394 nIndex = 0;
395 }
396
397 pSong->setLatestRoundRobin( fRoundRobinID, nIndex );
398 nLayerPicked = possibleLayersVector[ nIndex ];
399 break;
400 }
401
402 default:
403 ERRORLOG( QString( "Unknown selection algorithm [%1] for instrument [%2]" )
404 .arg( __instrument->sample_selection_alg() )
405 .arg( __instrument->get_name() ) );
406 return nullptr;
407 }
408
409 pSelectedLayer->nSelectedLayer = nLayerPicked;
410 auto pLayer = pInstrCompo->get_layer( nLayerPicked );
411 pSample = pLayer->get_sample();
412
413 } else {
414 ERRORLOG( "No samples found during random layer selection. This is a bug and shoul dn't happen!" );
415 }
416 }
417
418 return pSample;
419}
420
422{
423 float fNotePitch = __octave * KEYS_PER_OCTAVE + __key + __pitch;
424
425 if ( __instrument != nullptr ) {
426 fNotePitch += __instrument->get_pitch_offset();
427 }
428 return fNotePitch;
429}
430
432 // Due to the nature of the Gaussian distribution, the factors
433 // will also scale the standard deviations of the generated random
434 // variables.
435 const auto pSong = Hydrogen::get_instance()->getSong();
436 if ( pSong != nullptr ) {
437 const float fRandomVelocityFactor = pSong->getHumanizeVelocityValue();
438 if ( fRandomVelocityFactor != 0 ) {
439 set_velocity( __velocity + fRandomVelocityFactor *
441 }
442
443 const float fRandomTimeFactor = pSong->getHumanizeTimeValue();
444 if ( fRandomTimeFactor != 0 ) {
445 set_humanize_delay( __humanize_delay + fRandomTimeFactor *
448 }
449 }
450
451 if ( __instrument != nullptr ) {
452 const float fRandomPitchFactor = __instrument->get_random_pitch_factor();
453 if ( fRandomPitchFactor != 0 ) {
455 fRandomPitchFactor;
456 }
457 }
458}
459
461 const auto pSong = Hydrogen::get_instance()->getSong();
462 if ( pSong != nullptr && pSong->getSwingFactor() > 0 ) {
463 /* TODO: incorporate the factor MAX_NOTES / 32. either in
464 * Song::m_fSwingFactor or make it a member variable.
465 *
466 * comment by oddtime: 32 depends on the fact that the swing
467 * is applied to the upbeat 16th-notes. (not to upbeat
468 * 8th-notes as in jazz swing!). however 32 could be changed
469 * but must be >16, otherwise the max delay is too long and
470 * the swing note could be played after the next downbeat!
471 */
472 // If the Timeline is activated, the tick size may change at
473 // any point. Therefore, the length in frames of a 16-th note
474 // offset has to be calculated for a particular transport
475 // position and is not generally applicable.
476 double fTickMismatch;
479 __position + MAX_NOTES / 32., &fTickMismatch ) -
481 __position, &fTickMismatch ) ) *
482 pSong->getSwingFactor() );
483 }
484}
485
487{
488 node->write_int( "position", __position );
489 node->write_float( "leadlag", __lead_lag );
490 node->write_float( "velocity", __velocity );
491 node->write_float( "pan", m_fPan );
492 node->write_float( "pitch", __pitch );
493 node->write_string( "key", key_to_string() );
494 node->write_int( "length", __length );
495 node->write_int( "instrument", get_instrument()->get_id() );
496 node->write_bool( "note_off", __note_off );
497 node->write_float( "probability", __probability );
498}
499
500Note* Note::load_from( XMLNode* node, std::shared_ptr<InstrumentList> instruments, bool bSilent )
501{
502 bool bFound, bFound2;
503 float fPan = node->read_float( "pan", 0.f, &bFound, true, false, true );
504 if ( !bFound ) {
505 // check if pan is expressed in the old fashion (version <=
506 // 1.1 ) with the pair (pan_L, pan_R)
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 ) {
510 fPan = Sampler::getRatioPan( fPanL, fPanR ); // convert to single pan parameter
511 } else {
512 WARNINGLOG( QString( "Neither `pan` nor `pan_L` and `pan_R` were found. Falling back to `pan = 0`" ) );
513 }
514 }
515
516 Note* note = new Note(
517 nullptr,
518 node->read_int( "position", 0, false, false, bSilent ),
519 node->read_float( "velocity", 0.8f, false, false, bSilent ),
520 fPan,
521 node->read_int( "length", -1, true, false, bSilent ),
522 node->read_float( "pitch", 0.0f, false, false, bSilent )
523 );
524 note->set_lead_lag( node->read_float( "leadlag", 0, false, false, bSilent ) );
525 note->set_key_octave( node->read_string( "key", "C0", false, false, bSilent ) );
526 note->set_note_off( node->read_bool( "note_off", false, false, false, bSilent ) );
527 note->set_instrument_id( node->read_int( "instrument", EMPTY_INSTR_ID, false, false, bSilent ) );
528 note->map_instrument( instruments );
529 note->set_probability( node->read_float( "probability", 1.0f, false, false, bSilent ));
530
531 return note;
532}
533
534QString Note::toQString( const QString& sPrefix, bool bShort ) const {
535 QString s = Base::sPrintIndention;
536 QString sOutput;
537 if ( ! bShort ) {
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 ) ) );
553 } else {
554 sOutput.append( QString( "%1%2adsr: nullptr\n" ).arg( sPrefix ).arg( s ) );
555 }
556
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 ) );
571 if ( __instrument != nullptr ) {
572 sOutput.append( QString( "%1" ).arg( __instrument->toQString( sPrefix + s, bShort ) ) );
573 } else {
574 sOutput.append( QString( "%1%2instrument: nullptr\n" ).arg( sPrefix ).arg( s ) );
575 }
576 sOutput.append( QString( "%1%2layers_selected:\n" )
577 .arg( sPrefix ).arg( s ) );
578 for ( auto ll : __layers_selected ) {
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 )
582 .arg( ll.first )
583 .arg( ll.second->nSelectedLayer )
584 .arg( ll.second->fSamplePosition )
585 .arg( ll.second->nNoteLength ) );
586 } else {
587 sOutput.append( QString( "%1%2[component: %3, selected layer info: nullptr]\n" )
588 .arg( sPrefix ).arg( s + s )
589 .arg( ll.first ) );
590 }
591 }
592 } else {
593
594 sOutput = QString( "[Note]" )
595 .append( QString( ", instrument_id: %1" ).arg( __instrument_id ) )
596 .append( QString( ", specific_compo_id: %1" ).arg( __specific_compo_id ) )
597 .append( QString( ", position: %1" ).arg( __position ) )
598 .append( QString( ", m_nNoteStart: %1" ).arg( m_nNoteStart ) )
599 .append( QString( ", m_fUsedTickSize: %1" ).arg( m_fUsedTickSize ) )
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", "]" ) ) );
610 } else {
611 sOutput.append( ", adsr: nullptr" );
612 }
613
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 ) )
617 .append( QString( ", humanize_delay: %1" ).arg( __humanize_delay ) )
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 ) )
626 .append( QString( ", just_recorded: %1" ).arg( __just_recorded ) )
627 .append( QString( ", probability: %1" ).arg( __probability ) );
628 if ( __instrument != nullptr ) {
629 sOutput.append( QString( ", instrument: %1" ).arg( __instrument->get_name() ) );
630 } else {
631 sOutput.append( QString( ", instrument: nullptr" ) );
632 }
633 sOutput.append( QString( ", layers_selected: " ) );
634 for ( auto ll : __layers_selected ) {
635 if ( ll.second != nullptr ) {
636 sOutput.append( QString( "[component: %1, selected layer: %2, sample position: %3, note length: %4] " )
637 .arg( ll.first )
638 .arg( ll.second->nSelectedLayer )
639 .arg( ll.second->fSamplePosition )
640 .arg( ll.second->nNoteLength ) );
641 } else {
642 sOutput.append( QString( "[component: %1, selected layer info: nullptr]" )
643 .arg( ll.first ) );
644 }
645 }
646 }
647 return sOutput;
648}
649
650QString Note::KeyToQString( Key key ) {
651 QString s;
652
653 switch( key ) {
654 case Key::C:
655 s = QString( "C" );
656 break;
657 case Key::Cs:
658 s = QString( "Cs" );
659 break;
660 case Key::D:
661 s = QString( "D" );
662 break;
663 case Key::Ef:
664 s = QString( "Ef" );
665 break;
666 case Key::E:
667 s = QString( "E" );
668 break;
669 case Key::F:
670 s = QString( "F" );
671 break;
672 case Key::Fs:
673 s = QString( "Fs" );
674 break;
675 case Key::G:
676 s = QString( "G" );
677 break;
678 case Key::Af:
679 s = QString( "Af" );
680 break;
681 case Key::A:
682 s = QString( "A" );
683 break;
684 case Key::Bf:
685 s = QString( "Bf" );
686 break;
687 case Key::B:
688 s = QString( "B" );
689 break;
690 default:
691 ERRORLOG(QString( "Unknown Key value [%1]" ).arg( key ) );
692 }
693
694 return s;
695}
696};
697
698/* vim: set softtabstop=4 noexpandtab: */
#define EMPTY_INSTR_ID
Definition Instrument.h:34
#define VELOCITY_MAX
Definition Note.h:46
#define KEYS_PER_OCTAVE
Definition Note.h:40
#define LEAD_LAG_MIN
Definition Note.h:49
#define KEY_MAX
Definition Note.h:35
#define KEY_MIN
Definition Note.h:34
#define VELOCITY_MIN
Definition Note.h:45
#define LEAD_LAG_MAX
Definition Note.h:50
#define WARNINGLOG(x)
Definition Object.h:241
#define ERRORLOG(x)
Definition Object.h:242
#define ___ERRORLOG(x)
Definition Object.h:260
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.
Definition Object.h:127
std::shared_ptr< Song > getSong() const
Get the current song.
Definition Hydrogen.h:123
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:84
int get_position() const
__position accessor
Definition Note.h:534
int __humanize_delay
frequency [0;1]
Definition Note.h:456
float m_fUsedTickSize
TransportPosition::m_fTickSize used to calculate m_nNoteStart.
Definition Note.h:489
std::shared_ptr< SelectedLayerInfo > get_layer_selected(int CompoID)
Definition Note.h:619
float get_lpfb_r() const
__lpfb_r accessor
Definition Note.h:659
void swing()
Add swing contribution to __humanize_delay.
Definition Note.cpp:460
bool isPartiallyRendered() const
Definition Note.cpp:221
int __pattern_idx
index of the pattern holding this note for undo actions
Definition Note.h:462
float get_bpfb_r() const
__bpfb_r accessor
Definition Note.h:649
std::shared_ptr< Instrument > __instrument
the instrument to be played by this note
Definition Note.h:424
void set_lead_lag(float value)
__lead_lag setter
Definition Note.cpp:148
float get_resonance() const
__resonance accessor
Definition Note.h:639
static QString KeyToQString(Key key)
Definition Note.cpp:650
float m_fPan
pan of the note, [-1;1] from
Definition Note.h:430
float __lpfb_l
left low pass filter buffer
Definition Note.h:460
int __midi_msg
TODO.
Definition Note.h:463
void set_humanize_delay(int value)
__humanize_delay setter
Definition Note.cpp:157
void set_key_octave(const QString &str)
parse str and set __key and __octave
Definition Note.cpp:202
int __position
note position in
Definition Note.h:427
void map_instrument(std::shared_ptr< InstrumentList > instruments)
find the corresponding instrument and point to it, or an empty instrument
Definition Note.cpp:168
static Note * load_from(XMLNode *node, std::shared_ptr< InstrumentList > instruments, bool bSilent=false)
load a note from an XMLNode
Definition Note.cpp:500
float __resonance
filter resonant
Definition Note.h:445
Octave get_octave()
__octave accessor
Definition Note.h:676
void set_probability(float value)
Definition Note.h:614
int get_humanize_delay() const
__humanize_delay accessor
Definition Note.h:629
float __lead_lag
lead or lag offset of the note
Definition Note.h:443
std::shared_ptr< Instrument > get_instrument()
__instrument accessor
Definition Note.h:499
float get_bpfb_l() const
__bpfb_l accessor
Definition Note.h:644
int get_midi_msg() const
__midi_msg accessor
Definition Note.h:584
float get_total_pitch() const
Definition Note.cpp:421
bool __just_recorded
used in record+delete
Definition Note.h:465
float get_lead_lag() const
__lead_lag accessor
Definition Note.h:549
~Note()
destructor
Definition Note.cpp:134
float getUsedTickSize() const
Definition Note.h:749
void save_to(XMLNode *node)
Definition Note.cpp:486
float get_pitch() const
__pitch accessor
Definition Note.h:569
void humanize()
Add random contributions to __pitch, __humanize_delay, and __velocity.
Definition Note.cpp:431
int __length
left to right, as requested by Sampler PanLaws
Definition Note.h:438
std::shared_ptr< Sample > getSample(int nComponentID, int nSelectedLayer=-1)
Returns the sample associated with the note for a specific InstrumentComponent nComponentID.
Definition Note.cpp:262
int get_length() const
__length accessor
Definition Note.h:559
void set_instrument_id(int value)
__instrument_id setter
Definition Note.h:509
float __pitch
the frequency of the note
Definition Note.h:439
float __velocity
ticks inside the pattern
Definition Note.h:429
int get_pattern_idx() const
__pattern_idx accessor
Definition Note.h:594
float __probability
note probability
Definition Note.h:466
QString key_to_string()
return a string representation of key-octave
Definition Note.cpp:197
bool get_just_recorded() const
__just_recorded accessor
Definition Note.h:604
float get_velocity() const
__velocity accessor
Definition Note.h:539
Key
possible keys
Definition Note.h:105
bool get_note_off() const
__note_off accessor
Definition Note.h:579
void computeNoteStart()
Calculates the m_nNoteStart in frames corresponding to the __position in ticks and storing the used t...
Definition Note.cpp:234
void setPan(float val)
set pan of the note.
Definition Note.cpp:153
float __lpfb_r
right low pass filter buffer
Definition Note.h:461
void set_velocity(float value)
__velocity setter
Definition Note.cpp:143
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
Definition Note.cpp:534
float __cut_off
filter cutoff [0;1]
Definition Note.h:444
std::map< int, std::shared_ptr< SelectedLayerInfo > > __layers_selected
Definition Note.h:457
long long getNoteStart() const
Definition Note.h:746
std::shared_ptr< ADSR > __adsr
attack decay sustain release
Definition Note.h:442
void set_note_off(bool value)
__note_off setter
Definition Note.h:574
float get_cut_off() const
__cut_off accessor
Definition Note.h:634
bool __note_off
note type on|off
Definition Note.h:464
long long m_nNoteStart
from __key an __octave
Definition Note.h:475
Key get_key()
__key accessor
Definition Note.h:671
float __bpfb_l
left band pass filter buffer
Definition Note.h:458
Key __key
the key, [0;11]==[C;B]
Definition Note.h:440
float get_probability() const
Definition Note.h:609
Octave __octave
the octave [-3;3]
Definition Note.h:441
float get_lpfb_l() const
__lpfb_l accessor
Definition Note.h:654
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
Definition Note.cpp:45
Octave
possible octaves
Definition Note.h:109
float getPan() const
get pan of the note.
Definition Note.h:544
float __bpfb_r
right band pass filter buffer
Definition Note.h:459
int __instrument_id
the id of the instrument played by this note
Definition Note.h:425
int __specific_compo_id
play a specific component, -1 if playing all
Definition Note.h:426
static const char * __key_str[]
used to build QString
Definition Note.h:467
static float getGaussian(float fStandardDeviation)
Draws an uncorrelated random value from a Gaussian distribution of mean 0 and fStandardDeviation.
Definition Random.cpp:26
static float getRatioPan(float fPan_L, float fPan_R)
This function is used to load old version files (v<=1.1).
Definition Sampler.cpp:252
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.
Definition Xml.h:39
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
Definition Xml.cpp:151
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
Definition Xml.cpp:165
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
Definition Xml.cpp:76
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
Definition Xml.cpp:120
void write_float(const QString &node, const float value)
write a float into a child node
Definition Xml.cpp:261
void write_string(const QString &node, const QString &value)
write a string into a child node
Definition Xml.cpp:250
void write_bool(const QString &node, const bool value)
write a boolean into a child node
Definition Xml.cpp:269
void write_int(const QString &node, const int value)
write an integer into a child node
Definition Xml.cpp:265
#define MAX_NOTES
Maximum number of notes.
Definition config.dox:79
static float check_boundary(float fValue, float fMin, float fMax)
Definition Note.cpp:138