hydrogen 1.2.3
Instrument.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
24
25#include <cassert>
26
27#include <core/Hydrogen.h>
28
29#include <core/Helpers/Legacy.h>
30#include <core/Helpers/Xml.h>
31
32#include <core/Basics/Adsr.h>
33#include <core/Basics/Sample.h>
34#include <core/Basics/Drumkit.h>
41
42namespace H2Core
43{
44
45Instrument::Instrument( const int id, const QString& name, std::shared_ptr<ADSR> adsr )
46 : __id( id )
47 , __name( name )
48 , __gain( 1.0 )
49 , __volume( 1.0 )
50 , m_fPan( 0.f )
51 , __peak_l( 0.0 )
52 , __peak_r( 0.0 )
53 , __adsr( adsr )
54 , __filter_active( false )
55 , __filter_cutoff( 1.0 )
56 , __filter_resonance( 0.0 )
57 , __pitch_offset( 0.0 )
58 , __random_pitch_factor( 0.0 )
59 , __midi_out_note( 36 + id )
60 , __midi_out_channel( -1 )
61 , __stop_notes( false )
62 , __sample_selection_alg( VELOCITY )
63 , __active( true )
64 , __soloed( false )
65 , __muted( false )
66 , __mute_group( -1 )
67 , __queued( 0 )
68 , __hihat_grp( -1 )
69 , __lower_cc( 0 )
70 , __higher_cc( 127 )
71 , __components( nullptr )
72 , __is_preview_instrument(false)
73 , __is_metronome_instrument(false)
74 , __apply_velocity( true )
75 , __current_instr_for_export(false)
76 , m_bHasMissingSamples( false )
77{
78 if ( __adsr == nullptr ) {
79 __adsr = std::make_shared<ADSR>();
80 }
81
84 }
85
88 }
89
90 for ( int i=0; i<MAX_FX; i++ ) {
91 __fx_level[i] = 0.0;
92 }
93 __components = new std::vector<std::shared_ptr<InstrumentComponent>>();
94}
95
96Instrument::Instrument( std::shared_ptr<Instrument> other )
97 : __id( other->get_id() )
98 , __name( other->get_name() )
99 , __gain( other->__gain )
100 , __volume( other->get_volume() )
101 , m_fPan( other->getPan() )
102 , __peak_l( other->get_peak_l() )
103 , __peak_r( other->get_peak_r() )
104 , __adsr( std::make_shared<ADSR>( *( other->get_adsr() ) ) )
105 , __filter_active( other->is_filter_active() )
106 , __filter_cutoff( other->get_filter_cutoff() )
107 , __filter_resonance( other->get_filter_resonance() )
108 , __pitch_offset( other->get_pitch_offset() )
109 , __random_pitch_factor( other->get_random_pitch_factor() )
110 , __midi_out_note( other->get_midi_out_note() )
111 , __midi_out_channel( other->get_midi_out_channel() )
112 , __stop_notes( other->is_stop_notes() )
113 , __sample_selection_alg( other->sample_selection_alg() )
114 , __active( other->is_active() )
115 , __soloed( other->is_soloed() )
116 , __muted( other->is_muted() )
117 , __mute_group( other->get_mute_group() )
118 , __queued( other->is_queued() )
119 , __hihat_grp( other->get_hihat_grp() )
120 , __lower_cc( other->get_lower_cc() )
121 , __higher_cc( other->get_higher_cc() )
122 , __components( nullptr )
123 , __is_preview_instrument(false)
124 , __is_metronome_instrument(false)
125 , __apply_velocity( other->get_apply_velocity() )
126 , __current_instr_for_export(false)
127 , m_bHasMissingSamples(other->has_missing_samples())
128 , __drumkit_path( other->get_drumkit_path() )
129 , __drumkit_name( other->__drumkit_name )
130{
131 for ( int i=0; i<MAX_FX; i++ ) {
132 __fx_level[i] = other->get_fx_level( i );
133 }
134
135 __components = new std::vector<std::shared_ptr<InstrumentComponent>>();
136 for ( auto& pComponent : *other->get_components() ) {
137 __components->push_back( std::make_shared<InstrumentComponent>( pComponent ) );
138 }
139}
140
142{
143 delete __components;
144}
145
146std::shared_ptr<Instrument> Instrument::load_instrument( const QString& drumkit_path, const QString& instrument_name )
147{
148 auto pInstrument = std::make_shared<Instrument>();
149 pInstrument->load_from( drumkit_path, instrument_name );
150 return pInstrument;
151}
152
153void Instrument::load_from( std::shared_ptr<Drumkit> pDrumkit, std::shared_ptr<Instrument> pInstrument )
154{
155 assert( pDrumkit );
156 if ( pDrumkit == nullptr ) {
157 ERRORLOG( "Invalid drumkit supplied" );
158 return;
159 }
160
161 this->get_components()->clear();
162
163 set_missing_samples( false );
164
165 for ( const auto& pSrcComponent : *pInstrument->get_components() ) {
166 auto pMyComponent = std::make_shared<InstrumentComponent>( pSrcComponent->get_drumkit_componentID() );
167 pMyComponent->set_gain( pSrcComponent->get_gain() );
168
169 this->get_components()->push_back( pMyComponent );
170
171 for ( int i = 0; i < InstrumentComponent::getMaxLayers(); i++ ) {
172 auto src_layer = pSrcComponent->get_layer( i );
173 auto my_layer = pMyComponent->get_layer( i );
174
175 if( src_layer == nullptr ) {
176 pMyComponent->set_layer( nullptr, i );
177 }
178 else {
179 std::shared_ptr<Sample> pSample = nullptr;
180 QString sSamplePath;
181
182 if ( src_layer->get_sample() != nullptr ) {
183 QString sSamplePath = pDrumkit->get_path() + "/" + src_layer->get_sample()->get_filename();
184 pSample = Sample::load( sSamplePath );
185 }
186
187 if ( pSample == nullptr ) {
188 _ERRORLOG( QString( "Error loading sample %1. Creating a new empty layer." )
189 .arg( sSamplePath ) );
190 set_missing_samples( true );
191 pMyComponent->set_layer( nullptr, i );
192
193 }
194 else {
195 pSample->setLicense( pDrumkit->get_license() );
196 pMyComponent->set_layer( std::make_shared<InstrumentLayer>( src_layer, pSample ), i );
197 }
198 }
199 my_layer = nullptr;
200 }
201 }
202
203 this->set_id( pInstrument->get_id() );
204 this->set_name( pInstrument->get_name() );
205 this->set_drumkit_path( pDrumkit->get_path() );
206 this->set_drumkit_name( pDrumkit->get_name() );
207 this->set_gain( pInstrument->get_gain() );
208 this->set_volume( pInstrument->get_volume() );
209 this->setPan( pInstrument->getPan() );
210 this->set_adsr( std::make_shared<ADSR>( *( pInstrument->get_adsr() ) ) );
211 this->set_filter_active( pInstrument->is_filter_active() );
212 this->set_filter_cutoff( pInstrument->get_filter_cutoff() );
213 this->set_filter_resonance( pInstrument->get_filter_resonance() );
214 this->set_pitch_offset( pInstrument->get_pitch_offset() );
215 this->set_random_pitch_factor( pInstrument->get_random_pitch_factor() );
216 this->set_mute_group( pInstrument->get_mute_group() );
217 this->set_midi_out_channel( pInstrument->get_midi_out_channel() );
218 this->set_midi_out_note( pInstrument->get_midi_out_note() );
219 this->set_stop_notes( pInstrument->is_stop_notes() );
220 this->set_sample_selection_alg( pInstrument->sample_selection_alg() );
221 this->set_active( pInstrument->is_active() );
222 this->set_soloed( pInstrument->is_soloed() );
223 this->set_muted( pInstrument->is_muted() );
224 this->set_hihat_grp( pInstrument->get_hihat_grp() );
225 this->set_lower_cc( pInstrument->get_lower_cc() );
226 this->set_higher_cc( pInstrument->get_higher_cc() );
227 this->set_apply_velocity ( pInstrument->get_apply_velocity() );
228
229 for ( int ii = 0; ii < MAX_FX; ++ii ) {
230 this->set_fx_level( pInstrument->get_fx_level( ii ), ii );
231 }
232}
233
234void Instrument::load_from( const QString& sDrumkitPath, const QString& sInstrumentName )
235{
236 std::shared_ptr<Drumkit> pDrumkit;
237
238 // Try to retrieve the name from cache first.
239 auto pHydrogen = Hydrogen::get_instance();
240 if ( pHydrogen != nullptr ) {
241 pDrumkit = pHydrogen->getSoundLibraryDatabase()->getDrumkit( sDrumkitPath );
242 }
243
244 assert( pDrumkit );
245 if ( pDrumkit == nullptr ) {
246 ERRORLOG( QString( "Unable to load instrument: corresponding drumkit [%1] could not be loaded" )
247 .arg( sDrumkitPath ) );
248 return;
249 }
250
251 auto pInstrument = pDrumkit->get_instruments()->find( sInstrumentName );
252 if ( pInstrument != nullptr ) {
253 load_from( pDrumkit, pInstrument );
254 }
255 else {
256 ERRORLOG( QString( "Unable to load instrument: instrument [%1] could not be found in drumkit [%2]" )
257 .arg( sInstrumentName ).arg( sDrumkitPath ) );
258 }
259}
260
261std::shared_ptr<Instrument> Instrument::load_from( XMLNode* pNode, const QString& sDrumkitPath, const QString& sDrumkitName, const License& license, bool bSilent )
262{
263 // We use -2 instead of EMPTY_INSTR_ID (-1) to allow for loading
264 // empty instruments as well (e.g. during unit tests or as part of
265 // dummy kits)
266 int nId = pNode->read_int( "id", -2, false, false, bSilent );
267 if ( nId == -2 ) {
268 return nullptr;
269 }
270
271 auto pInstrument =
272 std::make_shared<Instrument>(
273 nId,
274 pNode->read_string( "name", "", false, false, bSilent ),
275 std::make_shared<ADSR>( pNode->read_int( "Attack", 0, true, false, bSilent ),
276 pNode->read_int( "Decay", 0, true, false, bSilent ),
277 pNode->read_float( "Sustain", 1.0f, true, false, bSilent ),
278 pNode->read_int( "Release", 1000, true, false, bSilent ) ) );
279
280 QString sInstrumentDrumkitPath, sInstrumentDrumkitName;
281 if ( sDrumkitPath.isEmpty() || sDrumkitName.isEmpty() ) {
282 // Instrument is not read as part of a Drumkit but as part of
283 // a Song. The drumkit meta info will be read from disk.
284 sInstrumentDrumkitName = pNode->read_string( "drumkit", "", false,
285 false, bSilent );
286
287 if ( ! pNode->firstChildElement( "drumkitPath" ).isNull() ) {
288 // Current format
289 sInstrumentDrumkitPath = pNode->read_string( "drumkitPath", "",
290 false, false, bSilent );
291
292#ifdef H2CORE_HAVE_APPIMAGE
293 sInstrumentDrumkitPath =
294 Filesystem::rerouteDrumkitPath( sInstrumentDrumkitPath );
295#endif
296
297 // Check whether corresponding drumkit exist.
298 // When tweaking or assembling drumkits locally their
299 // absolute paths serve as unique identifiers to keep them
300 // apart. But in terms of portability (and to assure
301 // backward compatibility) paths are bad and we will use
302 // the drumkit name and check whether we can find the kit
303 // on the local system.
304 if ( ! Filesystem::drumkit_valid( sInstrumentDrumkitPath ) ) {
305 WARNINGLOG( QString( "Couldn't find drumkit at [%1]. Searching for [%2] instead." )
306 .arg( sInstrumentDrumkitPath )
307 .arg( sInstrumentDrumkitName ) );
308 sInstrumentDrumkitPath = "";
309 }
310 }
311
312 if ( sInstrumentDrumkitPath.isEmpty() ) {
313 if ( ! pNode->firstChildElement( "drumkitLookup" ).isNull() ) {
314 // Format introduced in #1f2a06b and used in (at least)
315 // releases 1.1.0-beta1, 1.1.0, and 1.1.1.
316 //
317 // Using the additional lookup variable two drumkits holding
318 // the same name but one of the residing in user-space and
319 // the other one in system-space can be distinguished.
320 Filesystem::Lookup lookup =
321 static_cast<Filesystem::Lookup>(
322 pNode->read_int( "drumkitLookup",
323 static_cast<int>(Filesystem::Lookup::stacked),
324 false, false, bSilent ) );
325
326 sInstrumentDrumkitPath =
327 Filesystem::drumkit_path_search( sInstrumentDrumkitName,
328 lookup, true );
329
330 if ( sInstrumentDrumkitPath.isEmpty() &&
331 lookup != Filesystem::Lookup::stacked ) {
332 // Drumkit could not be found.
333 //
334 // It's possible the song was composed with a
335 // custom version of a system-level drumkit stored
336 // in user space. When loaded again in a fresh
337 // installed Hydrogen the custom user-level one
338 // will not be present anymore but it's plausible
339 // to fall back to the system-level one. (The
340 // other way around is also possible but much more
341 // unlikely. Nevertheless we will use the stacked
342 // search in one final effort)
343 sInstrumentDrumkitPath =
344 Filesystem::drumkit_path_search( sInstrumentDrumkitName,
346 true );
347
348 if ( sInstrumentDrumkitPath.isEmpty() ) {
349 ERRORLOG( QString( "Drumkit [%1] could neither found at system nor at user level." )
350 .arg( sInstrumentDrumkitName ) );
351 }
352 else if ( ! bSilent ) {
353 WARNINGLOG( QString( "Drumkit [%1] could not found using lookup type [%2]. Falling back to [%3] found using stacked search" )
354 .arg( sInstrumentDrumkitName )
355 .arg( static_cast<int>(lookup) )
356 .arg( sInstrumentDrumkitPath ) );
357 }
358 }
359 }
360 else if ( ! pNode->firstChildElement( "drumkit" ).isNull() ) {
361 // Format used from version 0.9.7 till 1.1.0.
362 //
363 // It features just the name of the drumkit an relies on
364 // it being unique throught the entire search path.
365 sInstrumentDrumkitPath =
366 Filesystem::drumkit_path_search( sInstrumentDrumkitName,
368 bSilent );
369 }
370 else {
371 // Format used prior to 0.9.7 which worked with absolute
372 // paths for the samples instead of relative ones.
373 sInstrumentDrumkitPath = "";
374 }
375 }
376 }
377 else {
378 sInstrumentDrumkitPath = sDrumkitPath;
379 sInstrumentDrumkitName = sDrumkitName;
380 }
381
382 pInstrument->set_drumkit_path( sInstrumentDrumkitPath );
383 pInstrument->__drumkit_name = sInstrumentDrumkitName;
384
385 pInstrument->set_volume( pNode->read_float( "volume", 1.0f,
386 true, true, bSilent ) );
387 pInstrument->set_muted( pNode->read_bool( "isMuted", false,
388 true, true, bSilent ) );
389 pInstrument->set_soloed( pNode->read_bool( "isSoloed", false,
390 true, false, true ) );
391 bool bFound, bFound2;
392 float fPan = pNode->read_float( "pan", 0.f, &bFound,
393 true, true, true );
394 if ( !bFound ) {
395 // check if pan is expressed in the old fashion (version <=
396 // 1.1 ) with the pair (pan_L, pan_R)
397 float fPanL = pNode->read_float( "pan_L", 1.f, &bFound,
398 true, true, bSilent );
399 float fPanR = pNode->read_float( "pan_R", 1.f, &bFound2,
400 true, true, bSilent );
401 if ( bFound == true && bFound2 == true ) { // found nodes pan_L and pan_R
402 fPan = Sampler::getRatioPan( fPanL, fPanR ); // convert to single pan parameter
403 }
404 }
405 pInstrument->setPan( fPan );
406
407 pInstrument->set_apply_velocity( pNode->read_bool( "applyVelocity", true,
408 false, true, bSilent ) );
409 pInstrument->set_filter_active( pNode->read_bool( "filterActive", true,
410 false, true, bSilent ) );
411 pInstrument->set_filter_cutoff( pNode->read_float( "filterCutoff", 1.0f,
412 true, false, bSilent ) );
413 pInstrument->set_filter_resonance( pNode->read_float( "filterResonance", 0.0f,
414 true, false, bSilent ) );
415 pInstrument->set_pitch_offset( pNode->read_float( "pitchOffset", 0.0f,
416 true, false, true ) );
417 pInstrument->set_random_pitch_factor( pNode->read_float( "randomPitchFactor", 0.0f,
418 true, false, bSilent ) );
419 pInstrument->set_gain( pNode->read_float( "gain", 1.0f,
420 true, false, bSilent ) );
421 pInstrument->set_mute_group( pNode->read_int( "muteGroup", -1,
422 true, false, bSilent ) );
423 pInstrument->set_midi_out_channel( pNode->read_int( "midiOutChannel", -1,
424 true, false, bSilent ) );
425 pInstrument->set_midi_out_note( pNode->read_int( "midiOutNote", pInstrument->__midi_out_note,
426 true, false, bSilent ) );
427 pInstrument->set_stop_notes( pNode->read_bool( "isStopNote", true,
428 false, true, bSilent ) );
429
430 QString sRead_sample_select_algo = pNode->read_string( "sampleSelectionAlgo", "VELOCITY",
431 true, true, bSilent );
432 if ( sRead_sample_select_algo.compare("VELOCITY") == 0 ) {
433 pInstrument->set_sample_selection_alg( VELOCITY );
434 }
435 else if ( sRead_sample_select_algo.compare("ROUND_ROBIN") == 0 ) {
436 pInstrument->set_sample_selection_alg( ROUND_ROBIN );
437 }
438 else if ( sRead_sample_select_algo.compare("RANDOM") == 0 ) {
439 pInstrument->set_sample_selection_alg( RANDOM );
440 }
441
442 pInstrument->set_hihat_grp( pNode->read_int( "isHihat", -1,
443 true, true, bSilent ) );
444 pInstrument->set_lower_cc( pNode->read_int( "lower_cc", 0,
445 true, true, bSilent ) );
446 pInstrument->set_higher_cc( pNode->read_int( "higher_cc", 127,
447 true, true, bSilent ) );
448
449 for ( int i=0; i<MAX_FX; i++ ) {
450 pInstrument->set_fx_level( pNode->read_float( QString( "FX%1Level" ).arg( i+1 ), 0.0,
451 true, true, bSilent ), i );
452 }
453
454 // This license will be applied to all samples contained in this
455 // instrument.
456 License instrumentLicense;
457 if ( license == License() ) {
458 // No/empty license supplied. We will use the license stored
459 // in the drumkit.xml file found in __drumkit_name. But since
460 // loading it from file is a rather expensive action, we will
461 // query it from the Drumkit database. If, for some reasons,
462 // the drumkit is not present yet, the License will be loaded
463 // directly.
464 auto pSoundLibraryDatabase = Hydrogen::get_instance()->getSoundLibraryDatabase();
465 if ( pSoundLibraryDatabase != nullptr ) {
466
467 // It is important to _not_ load the drumkit into the
468 // database as this code is part of the drumkit load
469 // itself. In case two drumkits contain an instrument from
470 // each other an infinite loop would be created.
471 auto pDrumkit = pSoundLibraryDatabase->getDrumkit(
472 pInstrument->get_drumkit_path(), false );
473 if ( pDrumkit == nullptr ) {
474 // Drumkit is not present in the database yet. Load
475 // its license from disk.
476 instrumentLicense = Drumkit::loadLicenseFrom( pInstrument->get_drumkit_path() );
477 } else {
478 instrumentLicense = pDrumkit->get_license();
479 }
480 }
481 } else {
482 instrumentLicense = license;
483 }
484
485 if ( ! pNode->firstChildElement( "instrumentComponent" ).isNull() ) {
486 // current format
487 XMLNode componentNode = pNode->firstChildElement( "instrumentComponent" );
488 while ( ! componentNode.isNull() ) {
489 pInstrument->get_components()->
490 push_back( InstrumentComponent::load_from( &componentNode,
491 pInstrument->get_drumkit_path(),
492 instrumentLicense, bSilent ) );
493 componentNode = componentNode.nextSiblingElement( "instrumentComponent" );
494 }
495 }
496 else {
497 // back compatibility code
498 auto pCompo = Legacy::loadInstrumentComponent( pNode, pInstrument->get_drumkit_path(),
499 instrumentLicense, bSilent );
500 if ( pCompo == nullptr ) {
501 ERRORLOG( QString( "Unable to load component for instrument [%1]. Aborting." )
502 .arg( pInstrument->get_name() ) );
503 return nullptr;
504 }
505
506 pInstrument->get_components()->push_back( pCompo );
507 }
508
509 // Sanity checks
510
511 // There has to be at least one InstrumentComponent
512 if ( pInstrument->get_components()->size() == 0 ) {
513 pInstrument->get_components()->push_back(
514 std::make_shared<InstrumentComponent>( 0 ) );
515 }
516
517 // Check whether there are missing samples
518 bool bSampleFound = false;
519 for ( const auto& pComponent : *pInstrument->get_components() ) {
520 if ( pComponent == nullptr ) {
521 ERRORLOG( "Invalid component. Something went wrong loading the instrument" );
522 pInstrument->set_muted( true );
523 pInstrument->set_missing_samples( true );
524 break;
525 }
526
527 for ( const auto& pLayer : *pComponent ) {
528 if ( pLayer == nullptr ) {
529 // The component is filled with nullptr up to
530 // InstrumentComponent::m_nMaxLayers.
531 continue;
532 }
533
534 if ( pLayer->get_sample() != nullptr ) {
535 if ( ! bSampleFound ) {
536 bSampleFound = true;
537 }
538 } else {
539 pInstrument->set_missing_samples( true );
540 }
541 }
542 }
543
544 if ( ! bSampleFound ) {
545 pInstrument->set_muted( true );
546 }
547
548 return pInstrument;
549}
550
551void Instrument::load_samples( float fBpm )
552{
553 for ( auto& pComponent : *get_components() ) {
554 for ( int i = 0; i < InstrumentComponent::getMaxLayers(); i++ ) {
555 auto pLayer = pComponent->get_layer( i );
556 if ( pLayer != nullptr ) {
557 pLayer->load_sample( fBpm );
558 }
559 }
560 }
561}
562
564{
565 for ( auto& pComponent : *get_components() ) {
566 for ( int i = 0; i < InstrumentComponent::getMaxLayers(); i++ ) {
567 auto pLayer = pComponent->get_layer( i );
568 if( pLayer ){
569 pLayer->unload_sample();
570 }
571 }
572 }
573}
574
575void Instrument::save_to( XMLNode* node, int component_id, bool bRecentVersion, bool bFull )
576{
577 XMLNode InstrumentNode = node->createNode( "instrument" );
578 InstrumentNode.write_int( "id", __id );
579 InstrumentNode.write_string( "name", __name );
580
581 if ( bFull ) {
582 InstrumentNode.write_string( "drumkitPath", __drumkit_path );
583 InstrumentNode.write_string( "drumkit", __drumkit_name );
584 }
585
586 InstrumentNode.write_float( "volume", __volume );
587 InstrumentNode.write_bool( "isMuted", __muted );
588 InstrumentNode.write_bool( "isSoloed", __soloed );
589
590 // We still store the pan using the old format to allow drumkits
591 // being created with Hydrogen versions v1.2 to be valid for prior
592 // versions too. After a couple of years and when all major Linux
593 // distributions ship a version >= 1.2 we can drop this part and
594 // just store the plain pan.
595 if ( getPan() >= 0.0 ) {
596 InstrumentNode.write_float( "pan_L", 1.0 - getPan() );
597 InstrumentNode.write_float( "pan_R", 1.0 );
598 }
599 else {
600 InstrumentNode.write_float( "pan_L", 1.0 );
601 InstrumentNode.write_float( "pan_R", getPan() + 1.0 );
602 }
603
604 InstrumentNode.write_float( "pitchOffset", __pitch_offset );
605 InstrumentNode.write_float( "randomPitchFactor", __random_pitch_factor );
606 InstrumentNode.write_float( "gain", __gain );
607 InstrumentNode.write_bool( "applyVelocity", __apply_velocity );
608 InstrumentNode.write_bool( "filterActive", __filter_active );
609 InstrumentNode.write_float( "filterCutoff", __filter_cutoff );
610 InstrumentNode.write_float( "filterResonance", __filter_resonance );
611 InstrumentNode.write_int( "Attack", __adsr->getAttack() );
612 InstrumentNode.write_int( "Decay", __adsr->getDecay() );
613 InstrumentNode.write_float( "Sustain", __adsr->getSustain() );
614 InstrumentNode.write_int( "Release", __adsr->getRelease() );
615 InstrumentNode.write_int( "muteGroup", __mute_group );
616 InstrumentNode.write_int( "midiOutChannel", __midi_out_channel );
617 InstrumentNode.write_int( "midiOutNote", __midi_out_note );
618 InstrumentNode.write_bool( "isStopNote", __stop_notes );
619
620 switch ( __sample_selection_alg ) {
621 case VELOCITY:
622 InstrumentNode.write_string( "sampleSelectionAlgo", "VELOCITY" );
623 break;
624 case RANDOM:
625 InstrumentNode.write_string( "sampleSelectionAlgo", "RANDOM" );
626 break;
627 case ROUND_ROBIN:
628 InstrumentNode.write_string( "sampleSelectionAlgo", "ROUND_ROBIN" );
629 break;
630 }
631
632 InstrumentNode.write_int( "isHihat", __hihat_grp );
633 InstrumentNode.write_int( "lower_cc", __lower_cc );
634 InstrumentNode.write_int( "higher_cc", __higher_cc );
635
636 for ( int i=0; i<MAX_FX; i++ ) {
637 InstrumentNode.write_float( QString( "FX%1Level" ).arg( i+1 ), __fx_level[i] );
638 }
639
640 for ( auto& pComponent : *__components ) {
641 if( component_id == -1 ||
642 pComponent->get_drumkit_componentID() == component_id ) {
643 pComponent->save_to( &InstrumentNode, component_id, bRecentVersion, bFull );
644 }
645 }
646}
647
648void Instrument::set_adsr( std::shared_ptr<ADSR> adsr )
649{
650 __adsr = adsr;
651}
652
653std::shared_ptr<InstrumentComponent> Instrument::get_component( int DrumkitComponentID )
654{
655 for ( const auto& pComponent : *get_components() ) {
656 if( pComponent->get_drumkit_componentID() == DrumkitComponentID ) {
657 return pComponent;
658 }
659 }
660
661 return nullptr;
662}
663
668
670 for ( const auto& pComponent : *__components ) {
671 if ( pComponent != nullptr ) {
672 for ( const auto& pLayer : *pComponent ) {
673 if ( pLayer != nullptr ) {
674 if ( pLayer->get_sample() != nullptr ) {
675 return true;
676 }
677 }
678 }
679 }
680 }
681
682 return false;
683}
684
685QString Instrument::toQString( const QString& sPrefix, bool bShort ) const {
686 QString s = Base::sPrintIndention;
687 QString sOutput;
688 if ( ! bShort ) {
689 sOutput = QString( "%1[Instrument]\n" ).arg( sPrefix )
690 .append( QString( "%1%2id: %3\n" ).arg( sPrefix ).arg( s ).arg( __id ) )
691 .append( QString( "%1%2name: %3\n" ).arg( sPrefix ).arg( s ).arg( __name ) )
692 .append( QString( "%1%2drumkit_path: %3\n" ).arg( sPrefix ).arg( s ).arg( __drumkit_path ) )
693 .append( QString( "%1%2drumkit_name: %3\n" ).arg( sPrefix ).arg( s ).arg( __drumkit_name ) )
694 .append( QString( "%1%2gain: %3\n" ).arg( sPrefix ).arg( s ).arg( __gain ) )
695 .append( QString( "%1%2volume: %3\n" ).arg( sPrefix ).arg( s ).arg( __volume ) )
696 .append( QString( "%1%2pan: %3\n" ).arg( sPrefix ).arg( s ).arg( m_fPan ) )
697 .append( QString( "%1%2peak_l: %3\n" ).arg( sPrefix ).arg( s ).arg( __peak_l ) )
698 .append( QString( "%1%2peak_r: %3\n" ).arg( sPrefix ).arg( s ).arg( __peak_r ) )
699 .append( QString( "%1" ).arg( __adsr->toQString( sPrefix + s, bShort ) ) )
700 .append( QString( "%1%2filter_active: %3\n" ).arg( sPrefix ).arg( s ).arg( __filter_active ) )
701 .append( QString( "%1%2filter_cutoff: %3\n" ).arg( sPrefix ).arg( s ).arg( __filter_cutoff ) )
702 .append( QString( "%1%2filter_resonance: %3\n" ).arg( sPrefix ).arg( s ).arg( __filter_resonance ) )
703 .append( QString( "%1%2random_pitch_factor: %3\n" ).arg( sPrefix ).arg( s ).arg( __random_pitch_factor ) )
704 .append( QString( "%1%2pitch_offset: %3\n" ).arg( sPrefix ).arg( s ).arg( __pitch_offset ) )
705 .append( QString( "%1%2midi_out_note: %3\n" ).arg( sPrefix ).arg( s ).arg( __midi_out_note ) )
706 .append( QString( "%1%2midi_out_channel: %3\n" ).arg( sPrefix ).arg( s ).arg( __midi_out_channel ) )
707 .append( QString( "%1%2stop_notes: %3\n" ).arg( sPrefix ).arg( s ).arg( __stop_notes ) )
708 .append( QString( "%1%2sample_selection_alg: %3\n" ).arg( sPrefix ).arg( s ).arg( __sample_selection_alg ) )
709 .append( QString( "%1%2active: %3\n" ).arg( sPrefix ).arg( s ).arg( __active ) )
710 .append( QString( "%1%2soloed: %3\n" ).arg( sPrefix ).arg( s ).arg( __soloed ) )
711 .append( QString( "%1%2muted: %3\n" ).arg( sPrefix ).arg( s ).arg( __muted ) )
712 .append( QString( "%1%2mute_group: %3\n" ).arg( sPrefix ).arg( s ).arg( __mute_group ) )
713 .append( QString( "%1%2queued: %3\n" ).arg( sPrefix ).arg( s ).arg( __queued ) ) ;
714 sOutput.append( QString( "%1%2fx_level: [ " ).arg( sPrefix ).arg( s ) );
715 for ( auto ff : __fx_level ) {
716 sOutput.append( QString( "%1 " ).arg( ff ) );
717 }
718 sOutput.append( QString( "]\n" ) )
719 .append( QString( "%1%2hihat_grp: %3\n" ).arg( sPrefix ).arg( s ).arg( __hihat_grp ) )
720 .append( QString( "%1%2lower_cc: %3\n" ).arg( sPrefix ).arg( s ).arg( __lower_cc ) )
721 .append( QString( "%1%2higher_cc: %3\n" ).arg( sPrefix ).arg( s ).arg( __higher_cc ) )
722 .append( QString( "%1%2is_preview_instrument: %3\n" ).arg( sPrefix ).arg( s ).arg( __is_preview_instrument ) )
723 .append( QString( "%1%2is_metronome_instrument: %3\n" ).arg( sPrefix ).arg( s ).arg( __is_metronome_instrument ) )
724 .append( QString( "%1%2apply_velocity: %3\n" ).arg( sPrefix ).arg( s ).arg( __apply_velocity ) )
725 .append( QString( "%1%2current_instr_for_export: %3\n" ).arg( sPrefix ).arg( s ).arg( __current_instr_for_export ) )
726 .append( QString( "%1%2m_bHasMissingSamples: %3\n" ).arg( sPrefix ).arg( s ).arg( m_bHasMissingSamples ) )
727 .append( QString( "%1%2components:\n" ).arg( sPrefix ).arg( s ) );
728 for ( auto cc : *__components ) {
729 if ( cc != nullptr ) {
730 sOutput.append( QString( "%1" ).arg( cc->toQString( sPrefix + s + s, bShort ) ) );
731 }
732 }
733 } else {
734
735 sOutput = QString( "[Instrument]" )
736 .append( QString( " id: %1" ).arg( __id ) )
737 .append( QString( ", name: %1" ).arg( __name ) )
738 .append( QString( ", drumkit_path: %1" ).arg( __drumkit_path ) )
739 .append( QString( ", drumkit_name: %1" ).arg( __drumkit_name ) )
740 .append( QString( ", gain: %1" ).arg( __gain ) )
741 .append( QString( ", volume: %1" ).arg( __volume ) )
742 .append( QString( ", pan: %1" ).arg( m_fPan ) )
743 .append( QString( ", peak_l: %1" ).arg( __peak_l ) )
744 .append( QString( ", peak_r: %1" ).arg( __peak_r ) )
745 .append( QString( ", [%1" ).arg( __adsr->toQString( sPrefix + s, bShort ).replace( "\n", "]" ) ) )
746 .append( QString( ", filter_active: %1" ).arg( __filter_active ) )
747 .append( QString( ", filter_cutoff: %1" ).arg( __filter_cutoff ) )
748 .append( QString( ", filter_resonance: %1" ).arg( __filter_resonance ) )
749 .append( QString( ", random_pitch_factor: %1" ).arg( __random_pitch_factor ) )
750 .append( QString( ", pitch_offset: %1" ).arg( __pitch_offset ) )
751 .append( QString( ", midi_out_note: %1" ).arg( __midi_out_note ) )
752 .append( QString( ", midi_out_channel: %1" ).arg( __midi_out_channel ) )
753 .append( QString( ", stop_notes: %1" ).arg( __stop_notes ) )
754 .append( QString( ", sample_selection_alg: %1" ).arg( __sample_selection_alg ) )
755 .append( QString( ", active: %1" ).arg( __active ) )
756 .append( QString( ", soloed: %1" ).arg( __soloed ) )
757 .append( QString( ", muted: %1" ).arg( __muted ) )
758 .append( QString( ", mute_group: %1" ).arg( __mute_group ) )
759 .append( QString( ", queued: %1" ).arg( __queued ) ) ;
760 sOutput.append( QString( ", fx_level: [ " ) );
761 for ( auto ff : __fx_level ) {
762 sOutput.append( QString( "%1 " ).arg( ff ) );
763 }
764 sOutput.append( QString( "]" ) )
765 .append( QString( ", hihat_grp: %1" ).arg( __hihat_grp ) )
766 .append( QString( ", lower_cc: %1" ).arg( __lower_cc ) )
767 .append( QString( ", higher_cc: %1" ).arg( __higher_cc ) )
768 .append( QString( ", is_preview_instrument: %1" ).arg( __is_preview_instrument ) )
769 .append( QString( ", is_metronome_instrument: %1" ).arg( __is_metronome_instrument ) )
770 .append( QString( ", apply_velocity: %1" ).arg( __apply_velocity ) )
771 .append( QString( ", current_instr_for_export: %1" ).arg( __current_instr_for_export ) )
772 .append( QString( ", m_bHasMissingSamples: %1" ).arg( m_bHasMissingSamples ) )
773 .append( QString( ", components: [" ) );
774 for ( auto cc : *__components ) {
775 if ( cc != nullptr ) {
776 sOutput.append( QString( " %1" ).arg( cc->get_drumkit_componentID() ) );
777 }
778 }
779 sOutput.append(" ]\n");
780 }
781
782 return sOutput;
783}
784
785};
786
787/* vim: set softtabstop=4 noexpandtab: */
#define WARNINGLOG(x)
Definition Object.h:238
#define ERRORLOG(x)
Definition Object.h:239
#define _ERRORLOG(x)
Definition Object.h:245
Attack Decay Sustain Release envelope.
Definition Adsr.h:38
static QString sPrintIndention
String used to format the debugging string output of some core classes.
Definition Object.h:127
static License loadLicenseFrom(const QString &sDrumkitDir, bool bSilent=false)
Loads the license information of a drumkit contained in directory sDrumkitDir.
Definition Drumkit.cpp:213
static QString ensure_session_compatibility(const QString &sPath)
If Hydrogen is under session management, we support for paths relative to the session folder.
static bool drumkit_valid(const QString &dk_path)
returns true if the path contains a usable drumkit
static QString rerouteDrumkitPath(const QString &sDrumkitPath)
Reroutes stored drumkit paths pointing to a temporary AppImage system data folder to the current AppI...
Lookup
Whenever a drumkit is loaded by name a collision between a user and a system drumkit carrying the sam...
Definition Filesystem.h:53
@ stacked
First, looks in the system drumkits and, afterwards, in the user drumkits.
static QString drumkit_path_search(const QString &dk_name, Lookup lookup=Lookup::stacked, bool bSilent=false)
Returns the path to a H2Core::Drumkit folder.
static Hydrogen * get_instance()
Returns the current Hydrogen instance __instance.
Definition Hydrogen.h:83
SoundLibraryDatabase * getSoundLibraryDatabase() const
Definition Hydrogen.h:94
static std::shared_ptr< InstrumentComponent > load_from(XMLNode *pNode, const QString &sDrumkitPath, const License &drumkitLicense=License(), bool bSilent=false)
QString __name
Name of the Instrument.
Definition Instrument.h:331
float __peak_r
right current peak value
Definition Instrument.h:352
float __pitch_offset
instrument main pitch offset
Definition Instrument.h:364
void set_name(const QString &name)
get the name of the instrument
Definition Instrument.h:389
int __hihat_grp
the instrument is part of a hihat
Definition Instrument.h:375
void set_pitch_offset(float val)
set the pitch offset of the instrument
Definition Instrument.h:575
bool __active
is the instrument active?
Definition Instrument.h:369
void set_drumkit_name(const QString &sName)
get the name of the related drumkits
Definition Instrument.h:681
bool __is_preview_instrument
is the instrument an hydrogen preview instrument?
Definition Instrument.h:378
void set_sample_selection_alg(SampleSelectionAlgo selected_algo)
Definition Instrument.h:636
~Instrument()
destructor
bool __is_metronome_instrument
is the instrument an metronome instrument?
Definition Instrument.h:379
static std::shared_ptr< Instrument > load_instrument(const QString &drumkit_path, const QString &instrument_name)
creates a new Instrument, loads samples from a given instrument within a given drumkit
void set_fx_level(float level, int index)
set the fx level of the instrument
Definition Instrument.h:560
bool __stop_notes
will the note automatically generate a note off after being on
Definition Instrument.h:367
void set_filter_resonance(float val)
set the filter resonance of the instrument
Definition Instrument.h:520
float m_fPan
pan of the instrument, [-1;1] from left to right, as requested by Sampler PanLaws
Definition Instrument.h:350
bool __soloed
is the instrument in solo mode?
Definition Instrument.h:370
int __midi_out_channel
midi out channel
Definition Instrument.h:366
float __random_pitch_factor
Factor to scale the random contribution when humanizing pitch between 0 and AudioEngine::fHumanizePit...
Definition Instrument.h:363
void set_drumkit_path(const QString &sPath)
get the path of the related drumkits
Definition Instrument.h:676
int __mute_group
mute group of the instrument
Definition Instrument.h:372
int __id
Identifier of an instrument, which should be unique.
Definition Instrument.h:328
void set_soloed(bool soloed)
set the soloed status of the instrument
Definition Instrument.h:600
void set_adsr(std::shared_ptr< ADSR > adsr)
set the ADSR of the instrument
void set_volume(float volume)
set the volume of the instrument
Definition Instrument.h:500
float __filter_resonance
filter resonant frequency (0..1)
Definition Instrument.h:356
float __filter_cutoff
filter cutoff (0..1)
Definition Instrument.h:355
void set_random_pitch_factor(float val)
set the random pitch factor of the instrument
Definition Instrument.h:570
QString __drumkit_name
Name of the #Drumkit found at __drumkit_path.
Definition Instrument.h:347
float __fx_level[MAX_FX]
Ladspa FX level array.
Definition Instrument.h:374
void set_filter_active(bool active)
activate the filter of the instrument
Definition Instrument.h:510
SampleSelectionAlgo __sample_selection_alg
how Hydrogen will chose the sample to use
Definition Instrument.h:368
void load_samples(float fBpm=120)
Calls the InstrumentLayer::load_sample() member function of all layers of each component of the Instr...
bool __muted
is the instrument muted?
Definition Instrument.h:371
bool __filter_active
is filter active?
Definition Instrument.h:354
float __gain
gain of the instrument
Definition Instrument.h:348
QString __drumkit_path
Path of the #Drumkit this Instrument belongs to.
Definition Instrument.h:339
std::shared_ptr< InstrumentComponent > get_component(int DrumkitComponentID)
void set_midi_out_channel(int channel)
set the midi out channel of the instrument
Definition Instrument.h:437
void set_apply_velocity(bool apply_velocity)
Definition Instrument.h:716
bool m_bHasMissingSamples
does the instrument have missing sample files?
Definition Instrument.h:383
void set_stop_notes(bool stopnotes)
set the stop notes status of the instrument
Definition Instrument.h:626
void set_gain(float gain)
set gain of the instrument
Definition Instrument.h:490
void set_midi_out_note(int note)
set the midi out note of the instrument
Definition Instrument.h:455
int __higher_cc
higher cc level
Definition Instrument.h:377
void set_hihat_grp(int hihat_grp)
Definition Instrument.h:646
void set_id(const int id)
get the id of the instrument
Definition Instrument.h:401
float __peak_l
left current peak value
Definition Instrument.h:351
void setPan(float val)
set pan of the instrument
Definition Instrument.h:474
void set_mute_group(int group)
set the mute group of the instrument
Definition Instrument.h:422
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
bool __current_instr_for_export
is the instrument currently being exported?
Definition Instrument.h:382
void set_active(bool active)
set the active status of the instrument
Definition Instrument.h:590
int __lower_cc
lower cc level
Definition Instrument.h:376
std::vector< std::shared_ptr< InstrumentComponent > > * __components
InstrumentLayer array.
Definition Instrument.h:380
std::shared_ptr< ADSR > __adsr
attack delay sustain release instance
Definition Instrument.h:353
void set_filter_cutoff(float val)
set the filter cutoff of the instrument
Definition Instrument.h:530
void unload_samples()
Calls the InstrumentLayer::unload_sample() member function of all layers of each component of the Ins...
float __volume
volume of the instrument
Definition Instrument.h:349
Instrument(const int id=EMPTY_INSTR_ID, const QString &name="Empty Instrument", std::shared_ptr< ADSR > adsr=nullptr)
constructor
void load_from(const QString &drumkit_path, const QString &instrument_name)
loads instrument from a given instrument within a given drumkit into a live Instrument object.
int __queued
count the number of notes queued within Sampler::__playing_notes_queue or std::priority_queue m_songN...
Definition Instrument.h:373
void set_missing_samples(bool bHasMissingSamples)
Definition Instrument.h:309
void set_higher_cc(int message)
Definition Instrument.h:666
void save_to(XMLNode *node, int component_id, bool bRecentVersion=true, bool bFull=false)
save the instrument within the given XMLNode
bool __apply_velocity
change the sample gain based on velocity
Definition Instrument.h:381
void set_lower_cc(int message)
Definition Instrument.h:656
std::vector< std::shared_ptr< InstrumentComponent > > * get_components()
Definition Instrument.h:711
float getPan() const
get pan of the instrument
Definition Instrument.h:485
QString get_drumkit_path() const
set the name of the related drumkit
void set_muted(bool muted)
set muted status of the instrument
Definition Instrument.h:464
int __midi_out_note
midi out note
Definition Instrument.h:365
bool hasSamples() const
Whether the instrument contains at least one non-missing sample.
static std::shared_ptr< InstrumentComponent > loadInstrumentComponent(XMLNode *pNode, const QString &sDrumkitPath, const License &drumkitLicense, bool bSilent=false)
Backward compatibility code to load an #InstrumentComponent from an #Instrument which itself did not ...
Definition Legacy.cpp:49
Wrapper class to help Hydrogen deal with the license information specified in a drumkit.
Definition License.h:48
static std::shared_ptr< Sample > load(const QString &filepath, const License &license=License())
Definition Sample.cpp:136
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
std::shared_ptr< Drumkit > getDrumkit(const QString &sDrumkitPath, bool bLoad=true)
Retrieve a drumkit from the database.
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
XMLNode createNode(const QString &name)
create a new XMLNode that has to be appended into de XMLDoc
Definition Xml.cpp:63
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_FX
Maximum number of effects.
Definition config.dox:83
#define MIDI_OUT_NOTE_MIN
Definition Globals.h:30
#define MIDI_OUT_NOTE_MAX
Definition Globals.h:31