hydrogen 1.2.3
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-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#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 ),
48 __specific_compo_id( -1 ),
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 ),
59 __humanize_delay( 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 ),
93 __specific_compo_id( -1 ),
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() ),
105 __humanize_delay( other->get_humanize_delay() ),
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() ),
113 __just_recorded( other->get_just_recorded() ),
114 __probability( other->get_probability() ),
115 m_nNoteStart( other->getNoteStart() ),
116 m_fUsedTickSize( other->getUsedTickSize() )
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
337 // are not set perfectly giving rise to some 'holes'.
338 // Occasionally the velocity of a note can fall into it
339 // causing the sampler to just skip it. Instead, we will
340 // search for the nearest sample and play this one instead.
341 if ( possibleLayersVector.size() == 0 ){
342 WARNINGLOG( QString( "Velocity [%1] did fall into a hole between the instrument layers for component [%2] of instrument [%3]." )
343 .arg( __velocity )
344 .arg( nComponentID )
345 .arg( __instrument->get_name() ) );
346
347 float shortestDistance = 1.0f;
348 int nearestLayer = -1;
349 for ( unsigned nLayer = 0; nLayer < InstrumentComponent::getMaxLayers(); ++nLayer ){
350 auto pLayer = pInstrCompo->get_layer( nLayer );
351 if ( pLayer == nullptr ){
352 continue;
353 }
354
355 if ( std::min( abs( pLayer->get_start_velocity() - __velocity ),
356 abs( pLayer->get_start_velocity() - __velocity ) ) <
357 shortestDistance ){
358 shortestDistance =
359 std::min( abs( pLayer->get_start_velocity() - __velocity ),
360 abs( pLayer->get_start_velocity() - __velocity ) );
361 nearestLayer = nLayer;
362 }
363 }
364
365 // Check whether the search was successful and assign the results.
366 if ( nearestLayer > -1 ){
367 possibleLayersVector.push_back( nearestLayer );
368 if ( __instrument->sample_selection_alg() == Instrument::ROUND_ROBIN ) {
369 fRoundRobinID =
370 pInstrCompo->get_layer( nearestLayer )->get_start_velocity();
371 }
372 } else {
373 ERRORLOG( QString( "No sample found for component [%1] of instrument [%2]" )
374 .arg( nComponentID ).arg( __instrument->get_name() ) );
375 return nullptr;
376 }
377 }
378
379 if( possibleLayersVector.size() > 0 ) {
380
381 int nLayerPicked;
382 switch ( __instrument->sample_selection_alg() ) {
384 nLayerPicked = possibleLayersVector[ 0 ];
385 break;
386
388 nLayerPicked = possibleLayersVector[ rand() %
389 possibleLayersVector.size() ];
390 break;
391
393 fRoundRobinID = __instrument->get_id() * 10 + fRoundRobinID;
394 int nIndex = pSong->getLatestRoundRobin( fRoundRobinID ) + 1;
395 if ( nIndex >= possibleLayersVector.size() ) {
396 nIndex = 0;
397 }
398
399 pSong->setLatestRoundRobin( fRoundRobinID, nIndex );
400 nLayerPicked = possibleLayersVector[ nIndex ];
401 break;
402 }
403
404 default:
405 ERRORLOG( QString( "Unknown selection algorithm [%1] for instrument [%2]" )
406 .arg( __instrument->sample_selection_alg() )
407 .arg( __instrument->get_name() ) );
408 return nullptr;
409 }
410
411 pSelectedLayer->nSelectedLayer = nLayerPicked;
412 auto pLayer = pInstrCompo->get_layer( nLayerPicked );
413 pSample = pLayer->get_sample();
414
415 } else {
416 ERRORLOG( "No samples found during random layer selection. This is a bug and shoul dn't happen!" );
417 }
418 }
419
420 return pSample;
421}
422
424{
425 float fNotePitch = __octave * KEYS_PER_OCTAVE + __key + __pitch;
426
427 if ( __instrument != nullptr ) {
428 fNotePitch += __instrument->get_pitch_offset();
429 }
430 return fNotePitch;
431}
432
434 // Due to the nature of the Gaussian distribution, the factors
435 // will also scale the standard deviations of the generated random
436 // variables.
437 const auto pSong = Hydrogen::get_instance()->getSong();
438 if ( pSong != nullptr ) {
439 const float fRandomVelocityFactor = pSong->getHumanizeVelocityValue();
440 if ( fRandomVelocityFactor != 0 ) {
441 set_velocity( __velocity + fRandomVelocityFactor *
443 }
444
445 const float fRandomTimeFactor = pSong->getHumanizeTimeValue();
446 if ( fRandomTimeFactor != 0 ) {
447 set_humanize_delay( __humanize_delay + fRandomTimeFactor *
450 }
451 }
452
453 if ( __instrument != nullptr ) {
454 const float fRandomPitchFactor = __instrument->get_random_pitch_factor();
455 if ( fRandomPitchFactor != 0 ) {
457 fRandomPitchFactor;
458 }
459 }
460}
461
463 const auto pSong = Hydrogen::get_instance()->getSong();
464 if ( pSong != nullptr && pSong->getSwingFactor() > 0 ) {
465 /* TODO: incorporate the factor MAX_NOTES / 32. either in
466 * Song::m_fSwingFactor or make it a member variable.
467 *
468 * comment by oddtime: 32 depends on the fact that the swing
469 * is applied to the upbeat 16th-notes. (not to upbeat
470 * 8th-notes as in jazz swing!). however 32 could be changed
471 * but must be >16, otherwise the max delay is too long and
472 * the swing note could be played after the next downbeat!
473 */
474 // If the Timeline is activated, the tick size may change at
475 // any point. Therefore, the length in frames of a 16-th note
476 // offset has to be calculated for a particular transport
477 // position and is not generally applicable.
478 double fTickMismatch;
481 __position + MAX_NOTES / 32., &fTickMismatch ) -
483 __position, &fTickMismatch ) ) *
484 pSong->getSwingFactor() );
485 }
486}
487
489{
490 node->write_int( "position", __position );
491 node->write_float( "leadlag", __lead_lag );
492 node->write_float( "velocity", __velocity );
493 node->write_float( "pan", m_fPan );
494 node->write_float( "pitch", __pitch );
495 node->write_string( "key", key_to_string() );
496 node->write_int( "length", __length );
497 node->write_int( "instrument", get_instrument()->get_id() );
498 node->write_bool( "note_off", __note_off );
499 node->write_float( "probability", __probability );
500}
501
502Note* Note::load_from( XMLNode* node, std::shared_ptr<InstrumentList> instruments, bool bSilent )
503{
504 bool bFound, bFound2;
505 float fPan = node->read_float( "pan", 0.f, &bFound, true, false, true );
506 if ( !bFound ) {
507 // check if pan is expressed in the old fashion (version <=
508 // 1.1 ) with the pair (pan_L, pan_R)
509 float fPanL = node->read_float( "pan_L", 1.f, &bFound, false, false, bSilent );
510 float fPanR = node->read_float( "pan_R", 1.f, &bFound2, false, false, bSilent );
511 if ( bFound && bFound2 ) {
512 fPan = Sampler::getRatioPan( fPanL, fPanR ); // convert to single pan parameter
513 } else {
514 WARNINGLOG( QString( "Neither `pan` nor `pan_L` and `pan_R` were found. Falling back to `pan = 0`" ) );
515 }
516 }
517
518 Note* note = new Note(
519 nullptr,
520 node->read_int( "position", 0, false, false, bSilent ),
521 node->read_float( "velocity", 0.8f, false, false, bSilent ),
522 fPan,
523 node->read_int( "length", -1, true, false, bSilent ),
524 node->read_float( "pitch", 0.0f, false, false, bSilent )
525 );
526 note->set_lead_lag( node->read_float( "leadlag", 0, false, false, bSilent ) );
527 note->set_key_octave( node->read_string( "key", "C0", false, false, bSilent ) );
528 note->set_note_off( node->read_bool( "note_off", false, false, false, bSilent ) );
529 note->set_instrument_id( node->read_int( "instrument", EMPTY_INSTR_ID, false, false, bSilent ) );
530 note->map_instrument( instruments );
531 note->set_probability( node->read_float( "probability", 1.0f, false, false, bSilent ));
532
533 return note;
534}
535
536QString Note::toQString( const QString& sPrefix, bool bShort ) const {
537 QString s = Base::sPrintIndention;
538 QString sOutput;
539 if ( ! bShort ) {
540 sOutput = QString( "%1[Note]\n" ).arg( sPrefix )
541 .append( QString( "%1%2instrument_id: %3\n" ).arg( sPrefix ).arg( s ).arg( __instrument_id ) )
542 .append( QString( "%1%2specific_compo_id: %3\n" ).arg( sPrefix ).arg( s ).arg( __specific_compo_id ) )
543 .append( QString( "%1%2position: %3\n" ).arg( sPrefix ).arg( s ).arg( __position ) )
544 .append( QString( "%1%2m_nNoteStart: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nNoteStart ) )
545 .append( QString( "%1%2m_fUsedTickSize: %3\n" ).arg( sPrefix ).arg( s ).arg( m_fUsedTickSize ) )
546 .append( QString( "%1%2velocity: %3\n" ).arg( sPrefix ).arg( s ).arg( __velocity ) )
547 .append( QString( "%1%2pan: %3\n" ).arg( sPrefix ).arg( s ).arg( m_fPan ) )
548 .append( QString( "%1%2length: %3\n" ).arg( sPrefix ).arg( s ).arg( __length ) )
549 .append( QString( "%1%2pitch: %3\n" ).arg( sPrefix ).arg( s ).arg( __pitch ) )
550 .append( QString( "%1%2key: %3\n" ).arg( sPrefix ).arg( s ).arg( __key ) )
551 .append( QString( "%1%2octave: %3\n" ).arg( sPrefix ).arg( s ).arg( __octave ) );
552 if ( __adsr != nullptr ) {
553 sOutput.append( QString( "%1" )
554 .arg( __adsr->toQString( sPrefix + s, bShort ) ) );
555 } else {
556 sOutput.append( QString( "%1%2adsr: nullptr\n" ).arg( sPrefix ).arg( s ) );
557 }
558
559 sOutput.append( QString( "%1%2lead_lag: %3\n" ).arg( sPrefix ).arg( s ).arg( __lead_lag ) )
560 .append( QString( "%1%2cut_off: %3\n" ).arg( sPrefix ).arg( s ).arg( __cut_off ) )
561 .append( QString( "%1%2resonance: %3\n" ).arg( sPrefix ).arg( s ).arg( __resonance ) )
562 .append( QString( "%1%2humanize_delay: %3\n" ).arg( sPrefix ).arg( s ).arg( __humanize_delay ) )
563 .append( QString( "%1%2key: %3\n" ).arg( sPrefix ).arg( s ).arg( __key ) )
564 .append( QString( "%1%2bpfb_l: %3\n" ).arg( sPrefix ).arg( s ).arg( __bpfb_l ) )
565 .append( QString( "%1%2bpfb_r: %3\n" ).arg( sPrefix ).arg( s ).arg( __bpfb_r ) )
566 .append( QString( "%1%2lpfb_l: %3\n" ).arg( sPrefix ).arg( s ).arg( __lpfb_l ) )
567 .append( QString( "%1%2lpfb_r: %3\n" ).arg( sPrefix ).arg( s ).arg( __lpfb_r ) )
568 .append( QString( "%1%2pattern_idx: %3\n" ).arg( sPrefix ).arg( s ).arg( __pattern_idx ) )
569 .append( QString( "%1%2midi_msg: %3\n" ).arg( sPrefix ).arg( s ).arg( __midi_msg ) )
570 .append( QString( "%1%2note_off: %3\n" ).arg( sPrefix ).arg( s ).arg( __note_off ) )
571 .append( QString( "%1%2just_recorded: %3\n" ).arg( sPrefix ).arg( s ).arg( __just_recorded ) )
572 .append( QString( "%1%2probability: %3\n" ).arg( sPrefix ).arg( s ).arg( __probability ) );
573 if ( __instrument != nullptr ) {
574 sOutput.append( QString( "%1" ).arg( __instrument->toQString( sPrefix + s, bShort ) ) );
575 } else {
576 sOutput.append( QString( "%1%2instrument: nullptr\n" ).arg( sPrefix ).arg( s ) );
577 }
578 sOutput.append( QString( "%1%2layers_selected:\n" )
579 .arg( sPrefix ).arg( s ) );
580 for ( auto ll : __layers_selected ) {
581 if ( ll.second != nullptr ) {
582 sOutput.append( QString( "%1%2[component: %3, selected layer: %4, sample position: %5, note length: %6]\n" )
583 .arg( sPrefix ).arg( s + s )
584 .arg( ll.first )
585 .arg( ll.second->nSelectedLayer )
586 .arg( ll.second->fSamplePosition )
587 .arg( ll.second->nNoteLength ) );
588 } else {
589 sOutput.append( QString( "%1%2[component: %3, selected layer info: nullptr]\n" )
590 .arg( sPrefix ).arg( s + s )
591 .arg( ll.first ) );
592 }
593 }
594 } else {
595
596 sOutput = QString( "[Note]" )
597 .append( QString( ", instrument_id: %1" ).arg( __instrument_id ) )
598 .append( QString( ", specific_compo_id: %1" ).arg( __specific_compo_id ) )
599 .append( QString( ", position: %1" ).arg( __position ) )
600 .append( QString( ", m_nNoteStart: %1" ).arg( m_nNoteStart ) )
601 .append( QString( ", m_fUsedTickSize: %1" ).arg( m_fUsedTickSize ) )
602 .append( QString( ", velocity: %1" ).arg( __velocity ) )
603 .append( QString( ", pan: %1" ).arg( m_fPan ) )
604 .append( QString( ", length: %1" ).arg( __length ) )
605 .append( QString( ", pitch: %1" ).arg( __pitch ) )
606 .append( QString( ", key: %1" ).arg( __key ) )
607 .append( QString( ", octave: %1" ).arg( __octave ) );
608 if ( __adsr != nullptr ) {
609 sOutput.append( QString( ", [%1" )
610 .arg( __adsr->toQString( sPrefix + s, bShort )
611 .replace( "\n", "]" ) ) );
612 } else {
613 sOutput.append( ", adsr: nullptr" );
614 }
615
616 sOutput.append( QString( ", lead_lag: %1" ).arg( __lead_lag ) )
617 .append( QString( ", cut_off: %1" ).arg( __cut_off ) )
618 .append( QString( ", resonance: %1" ).arg( __resonance ) )
619 .append( QString( ", humanize_delay: %1" ).arg( __humanize_delay ) )
620 .append( QString( ", key: %1" ).arg( __key ) )
621 .append( QString( ", bpfb_l: %1" ).arg( __bpfb_l ) )
622 .append( QString( ", bpfb_r: %1" ).arg( __bpfb_r ) )
623 .append( QString( ", lpfb_l: %1" ).arg( __lpfb_l ) )
624 .append( QString( ", lpfb_r: %1" ).arg( __lpfb_r ) )
625 .append( QString( ", pattern_idx: %1" ).arg( __pattern_idx ) )
626 .append( QString( ", midi_msg: %1" ).arg( __midi_msg ) )
627 .append( QString( ", note_off: %1" ).arg( __note_off ) )
628 .append( QString( ", just_recorded: %1" ).arg( __just_recorded ) )
629 .append( QString( ", probability: %1" ).arg( __probability ) );
630 if ( __instrument != nullptr ) {
631 sOutput.append( QString( ", instrument: %1" ).arg( __instrument->get_name() ) );
632 } else {
633 sOutput.append( QString( ", instrument: nullptr" ) );
634 }
635 sOutput.append( QString( ", layers_selected: " ) );
636 for ( auto ll : __layers_selected ) {
637 if ( ll.second != nullptr ) {
638 sOutput.append( QString( "[component: %1, selected layer: %2, sample position: %3, note length: %4] " )
639 .arg( ll.first )
640 .arg( ll.second->nSelectedLayer )
641 .arg( ll.second->fSamplePosition )
642 .arg( ll.second->nNoteLength ) );
643 } else {
644 sOutput.append( QString( "[component: %1, selected layer info: nullptr]" )
645 .arg( ll.first ) );
646 }
647 }
648 }
649 return sOutput;
650}
651
652QString Note::KeyToQString( Key key ) {
653 QString s;
654
655 switch( key ) {
656 case Key::C:
657 s = QString( "C" );
658 break;
659 case Key::Cs:
660 s = QString( "Cs" );
661 break;
662 case Key::D:
663 s = QString( "D" );
664 break;
665 case Key::Ef:
666 s = QString( "Ef" );
667 break;
668 case Key::E:
669 s = QString( "E" );
670 break;
671 case Key::F:
672 s = QString( "F" );
673 break;
674 case Key::Fs:
675 s = QString( "Fs" );
676 break;
677 case Key::G:
678 s = QString( "G" );
679 break;
680 case Key::Af:
681 s = QString( "Af" );
682 break;
683 case Key::A:
684 s = QString( "A" );
685 break;
686 case Key::Bf:
687 s = QString( "Bf" );
688 break;
689 case Key::B:
690 s = QString( "B" );
691 break;
692 default:
693 ERRORLOG(QString( "Unknown Key value [%1]" ).arg( key ) );
694 }
695
696 return s;
697}
698};
699
700/* vim: set softtabstop=4 noexpandtab: */
#define EMPTY_INSTR_ID
Definition Instrument.h:34
#define VELOCITY_MAX
Definition Note.h:44
#define KEYS_PER_OCTAVE
Definition Note.h:38
#define LEAD_LAG_MIN
Definition Note.h:47
#define KEY_MAX
Definition Note.h:33
#define KEY_MIN
Definition Note.h:32
#define VELOCITY_MIN
Definition Note.h:43
#define LEAD_LAG_MAX
Definition Note.h:48
#define WARNINGLOG(x)
Definition Object.h:238
#define ERRORLOG(x)
Definition Object.h:239
#define ___ERRORLOG(x)
Definition Object.h:257
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:122
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:83
A note plays an associated instrument with a velocity left and right pan.
Definition Note.h:102
int __humanize_delay
frequency [0;1]
Definition Note.h:457
float m_fUsedTickSize
TransportPosition::m_fTickSize used to calculate m_nNoteStart.
Definition Note.h:490
std::shared_ptr< SelectedLayerInfo > get_layer_selected(int CompoID)
Definition Note.h:620
void swing()
Add swing contribution to __humanize_delay.
Definition Note.cpp:462
bool isPartiallyRendered() const
Definition Note.cpp:221
int __pattern_idx
index of the pattern holding this note for undo actions
Definition Note.h:463
std::shared_ptr< Instrument > __instrument
the instrument to be played by this note
Definition Note.h:425
void set_lead_lag(float value)
__lead_lag setter
Definition Note.cpp:148
static QString KeyToQString(Key key)
Definition Note.cpp:652
float m_fPan
pan of the note, [-1;1] from
Definition Note.h:431
float __lpfb_l
left low pass filter buffer
Definition Note.h:461
int __midi_msg
TODO.
Definition Note.h:464
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:428
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:502
float __resonance
filter resonant
Definition Note.h:446
void set_probability(float value)
Definition Note.h:615
float __lead_lag
lead or lag offset of the note
Definition Note.h:444
std::shared_ptr< Instrument > get_instrument()
__instrument accessor
Definition Note.h:500
float get_total_pitch() const
Definition Note.cpp:423
bool __just_recorded
used in record+delete
Definition Note.h:466
~Note()
destructor
Definition Note.cpp:134
void save_to(XMLNode *node)
Definition Note.cpp:488
void humanize()
Add random contributions to __pitch, __humanize_delay, and __velocity.
Definition Note.cpp:433
int __length
left to right, as requested by Sampler PanLaws
Definition Note.h:439
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
void set_instrument_id(int value)
__instrument_id setter
Definition Note.h:510
float __pitch
the frequency of the note
Definition Note.h:440
float __velocity
ticks inside the pattern
Definition Note.h:430
float __probability
note probability
Definition Note.h:467
QString key_to_string()
return a string representation of key-octave
Definition Note.cpp:197
Key
possible keys
Definition Note.h:106
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:462
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:536
float __cut_off
filter cutoff [0;1]
Definition Note.h:445
std::map< int, std::shared_ptr< SelectedLayerInfo > > __layers_selected
Definition Note.h:458
std::shared_ptr< ADSR > __adsr
attack decay sustain release
Definition Note.h:443
void set_note_off(bool value)
__note_off setter
Definition Note.h:575
bool __note_off
note type on|off
Definition Note.h:465
long long m_nNoteStart
from __key an __octave
Definition Note.h:476
float __bpfb_l
left band pass filter buffer
Definition Note.h:459
Key __key
the key, [0;11]==[C;B]
Definition Note.h:441
Octave __octave
the octave [-3;3]
Definition Note.h:442
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:110
float __bpfb_r
right band pass filter buffer
Definition Note.h:460
int __instrument_id
the id of the instrument played by this note
Definition Note.h:426
int __specific_compo_id
play a specific component, -1 if playing all
Definition Note.h:427
static const char * __key_str[]
used to build QString
Definition Note.h:468
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:257
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:170
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:184
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:95
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:139
void write_float(const QString &node, const float value)
write a float into a child node
Definition Xml.cpp:280
void write_string(const QString &node, const QString &value)
write a string into a child node
Definition Xml.cpp:269
void write_bool(const QString &node, const bool value)
write a boolean into a child node
Definition Xml.cpp:288
void write_int(const QString &node, const int value)
write an integer into a child node
Definition Xml.cpp:284
#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