hydrogen 1.2.6
Future.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2008-2025 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
4 *
5 * http://www.hydrogen-music.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY, without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see https://www.gnu.org/licenses
19 *
20 */
21
22#include <core/Helpers/Future.h>
23
24#include <core/Helpers/Xml.h>
25#include <core/Basics/Drumkit.h>
30
31namespace H2Core {
32
33std::shared_ptr<H2Core::Drumkit> Future::loadDrumkit( XMLNode& node,
34 const QString& sDrumkitPath,
35 bool bSilent ) {
36 QString sDrumkitName = node.read_string( "name", "", false, false, bSilent );
37 if ( sDrumkitName.isEmpty() ) {
38 ERRORLOG( "Drumkit has no name, abort" );
39 return nullptr;
40 }
41
42 std::shared_ptr<Drumkit> pDrumkit = std::make_shared<Drumkit>();
43 pDrumkit->set_path( sDrumkitPath );
44 pDrumkit->set_name( sDrumkitName );
45 pDrumkit->set_author( node.read_string( "author", "undefined author",
46 true, true, true ) );
47 pDrumkit->set_info( node.read_string( "info", "No information available.",
48 true, true, bSilent ) );
49
50 License license( node.read_string( "license", "undefined license",
51 true, true, bSilent ),
52 pDrumkit->get_author() );
53 pDrumkit->set_license( license );
54
55 // As of 2022 we have no drumkits featuring an image in
56 // stock. Thus, verbosity of this one will be turned of in order
57 // to make to log more concise.
58 pDrumkit->set_image( node.read_string( "image", "",
59 true, true, true ) );
60 License imageLicense( node.read_string( "imageLicense", "undefined license",
61 true, true, true ),
62 pDrumkit->get_author() );
63 pDrumkit->set_image_license( imageLicense );
64
65 // There are no DrumkitComponents in more recent versions of the drumkit.
66 // Instead, each Instrument can have several, independent
67 // InstrumentComponents all holding their individual name but no component
68 // ID as present in 1.2.X.
69 //
70 // We will load those instruments one by one, take care of mapping the
71 // individual component names to DrumkitComponents - InstrumentComponents
72 // holding the same name will be associated to the same DrumkitComponent -
73 // and add these instrument to the drumkit one by one.
74 //
75 // Map uses the component name as key and the new component ID as value.
76 std::map<QString, int> componentMap;
77 int nNextComponentId = 0;
78
79 // We load the instruments piece by piece and add them to the drumkit.
80 XMLNode instrumentListNode = node.firstChildElement( "instrumentList" );
81 if ( instrumentListNode.isNull() ) {
82 ERRORLOG( "'instrumentList' node not found. Unable to load instrument list." );
83 return nullptr;
84 }
85
86 auto pInstrumentList = std::make_shared<InstrumentList>();
87 XMLNode instrumentNode = instrumentListNode.firstChildElement( "instrument" );
88 int nCount = 0;
89 while ( !instrumentNode.isNull() ) {
90 nCount++;
91 if ( nCount > MAX_INSTRUMENTS ) {
92 ERRORLOG( QString( "instrument nCount >= %1 (MAX_INSTRUMENTS), stop reading instruments" )
93 .arg( MAX_INSTRUMENTS ) );
94 break;
95 }
96
97 auto pInstrument = Instrument::load_from(
98 &instrumentNode, sDrumkitPath, sDrumkitName, license, nullptr,
99 bSilent );
100 if ( pInstrument != nullptr ) {
101 auto pInstrumentComponents = pInstrument->get_components();
102
103 // The stock loading method of Instrument does not retrieve is
104 // component's name.
105 //
106 // In addition, the sample selection algorithm was moved on
107 // component level. In versions of Hydrogen < 2.0, however, it is
108 // still present on instrument level. We will use the last one
109 // encountered.
111 XMLNode componentNode =
112 instrumentNode.firstChildElement( "instrumentComponent" );
113 int nnComponentIdx = 0;
114 int nnComponentId;
115 while ( ! componentNode.isNull() ) {
116 const QString ssComponentName =
117 componentNode.read_string( "name", "Main", false, false );
118 if ( auto search = componentMap.find( ssComponentName );
119 search != componentMap.end() ) {
120 // Component name already encountered.
121 nnComponentId = componentMap[ ssComponentName ];
122 }
123 else {
124 // The corresponding drumkit component does not exist yet.
125 nnComponentId = nNextComponentId;
126 auto pDrumkitComponent = std::make_shared<DrumkitComponent>(
127 nnComponentId, ssComponentName );
128 pDrumkit->addComponent( pDrumkitComponent );
129 componentMap[ ssComponentName ] = nnComponentId;
130 nNextComponentId++;
131 }
132
133 if ( nnComponentIdx < pInstrumentComponents->size() ) {
134 auto pInstrumentComponent =
135 pInstrumentComponents->at( nnComponentIdx );
136 if ( pInstrumentComponent != nullptr ) {
137 pInstrumentComponent->set_drumkit_componentID(
138 nnComponentId );
139 }
140 else {
141 ERRORLOG( QString( "Unable to access component [%1] of instrument [%2]" )
142 .arg( nnComponentIdx )
143 .arg( pInstrument->get_name() ) );
144 }
145 }
146 else {
147 ERRORLOG( QString( "Component number [%1] out of bound [0,%2] for instrument [%3]" )
148 .arg( nnComponentIdx )
149 .arg( pInstrumentComponents->size() )
150 .arg( pInstrument->get_name() ) );
151 }
152
153 // Retrieve the sample selection algorithm.
154 const QString sSelection = componentNode.read_string(
155 "sampleSelectionAlgo", "", true, true, bSilent );
156 if ( sSelection.compare( "VELOCITY" ) == 0 ) {
158 }
159 else if ( sSelection.compare( "ROUND_ROBIN" ) == 0 ) {
161 }
162 else if ( sSelection.compare( "RANDOM" ) == 0 ) {
164 }
165
166 ++nnComponentIdx;
167 componentNode = componentNode.nextSiblingElement( "instrumentComponent" );
168 }
169
170 pInstrument->set_sample_selection_alg( selection );
171
172 pDrumkit->addInstrument( pInstrument );
173 }
174 else {
175 ERRORLOG( QString( "Unable to load instrument [%1]. The drumkit is corrupted. Skipping instrument" )
176 .arg( nCount ) );
177 nCount--;
178 }
179 instrumentNode = instrumentNode.nextSiblingElement( "instrument" );
180 }
181
182 if ( nCount == 0 ) {
183 ERRORLOG( "Newly created instrument list does not contain any instruments. Aborting." );
184 return nullptr;
185 }
186
187 return pDrumkit;
188
189}
190
191std::vector<std::shared_ptr<DrumkitComponent>> Future::loadDrumkitComponentsFromKit( XMLNode* pNode ) {
192 std::vector<std::shared_ptr<DrumkitComponent>> pComponents;
193 XMLNode componentListNode = pNode->firstChildElement( "componentList" );
194 if ( ! componentListNode.isNull() ) {
195 XMLNode componentNode = componentListNode.firstChildElement( "drumkitComponent" );
196 while ( ! componentNode.isNull() ) {
197 auto pDrumkitComponent = DrumkitComponent::load_from(
198 &componentNode, nullptr );
199 if ( pDrumkitComponent != nullptr ) {
200 pComponents.push_back(pDrumkitComponent);
201 }
202
203 componentNode = componentNode.nextSiblingElement( "drumkitComponent" );
204 }
205 } else {
206 WARNINGLOG( "componentList node not found" );
207 auto pDrumkitComponent = std::make_shared<DrumkitComponent>( 0, "Main" );
208 pComponents.push_back(pDrumkitComponent);
209 }
210
211 return std::move( pComponents );
212}
213};
#define WARNINGLOG(x)
Definition Object.h:241
#define ERRORLOG(x)
Definition Object.h:242
static std::shared_ptr< DrumkitComponent > load_from(XMLNode *node, bool *pLegacyFormatEncountered=nullptr)
static std::shared_ptr< H2Core::Drumkit > loadDrumkit(XMLNode &node, const QString &sDrumkitPath, bool bSilent=false)
Definition Future.cpp:33
static std::vector< std::shared_ptr< DrumkitComponent > > loadDrumkitComponentsFromKit(XMLNode *pNode)
Definition Future.cpp:191
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.
Wrapper class to help Hydrogen deal with the license information specified in a drumkit.
Definition License.h:48
XMLNode is a subclass of QDomNode with read and write values methods.
Definition Xml.h:39
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
#define MAX_INSTRUMENTS
Maximum number of instruments allowed in Hydrogen.
Definition config.dox:70