hydrogen 1.2.6
InstrumentComponent.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
24
25#include <cassert>
26
28
29#include <core/Helpers/Xml.h>
31#include <core/License.h>
32
33#include <core/Basics/Adsr.h>
34#include <core/Basics/Sample.h>
35#include <core/Basics/Drumkit.h>
40
41namespace H2Core
42{
43
45
46InstrumentComponent::InstrumentComponent( int related_drumkit_componentID )
47 : __related_drumkit_componentID( related_drumkit_componentID )
48 , __gain( 1.0 )
49{
50 __layers.resize( m_nMaxLayers );
51 for ( int i = 0; i < m_nMaxLayers; i++ ) {
52 __layers[i] = nullptr;
53 }
54}
55
56InstrumentComponent::InstrumentComponent( std::shared_ptr<InstrumentComponent> other )
58 , __gain( other->__gain )
59{
60 __layers.resize( m_nMaxLayers );
61 for ( int i = 0; i < m_nMaxLayers; i++ ) {
62 std::shared_ptr<InstrumentLayer> other_layer = other->get_layer( i );
63 if ( other_layer ) {
64 __layers[i] = std::make_shared<InstrumentLayer>( other_layer );
65 } else {
66 __layers[i] = nullptr;
67 }
68 }
69}
70
72{
73 for ( int i = 0; i < m_nMaxLayers; i++ ) {
74 __layers[i] = nullptr;
75 }
76}
77
78void InstrumentComponent::set_layer( std::shared_ptr<InstrumentLayer> layer, int idx )
79{
80 assert( idx >= 0 && idx < m_nMaxLayers );
81 __layers[ idx ] = layer;
82}
83
85{
86 m_nMaxLayers = layers;
87}
88
93
94std::shared_ptr<InstrumentComponent> InstrumentComponent::load_from( XMLNode* pNode, const QString& sDrumkitPath, const License& drumkitLicense, bool bSilent )
95{
96 // Component IDs are essential. But in InstrumentComponents created in
97 // version >= v2.0 they are not present anymore. Instead, we just fallback
98 // to the default value and replace them at a later point of the loading
99 // process.
100 int nId = pNode->read_int( "component_id", EMPTY_INSTR_ID,
101 true, false, true );
102
103 auto pInstrumentComponent = std::make_shared<InstrumentComponent>( nId );
104 pInstrumentComponent->set_gain( pNode->read_float( "gain", 1.0f,
105 true, false, bSilent ) );
106 XMLNode layer_node = pNode->firstChildElement( "layer" );
107 int nLayer = 0;
108 while ( ! layer_node.isNull() ) {
109 if ( nLayer >= m_nMaxLayers ) {
110 ERRORLOG( QString( "Layer #%1 >= m_nMaxLayers (%2). This as well as all further layers will be omitted." )
111 .arg( nLayer ).arg( m_nMaxLayers ) );
112 break;
113 }
114
115 auto pLayer = InstrumentLayer::load_from( &layer_node, sDrumkitPath,
116 drumkitLicense, bSilent );
117 if ( pLayer != nullptr ) {
118 pInstrumentComponent->set_layer( pLayer, nLayer );
119 nLayer++;
120 }
121 layer_node = layer_node.nextSiblingElement( "layer" );
122 }
123
124 return pInstrumentComponent;
125}
126
127void InstrumentComponent::save_to( XMLNode* node, int component_id, bool bRecentVersion, bool bFull )
128{
129 XMLNode component_node;
130 if ( bRecentVersion ) {
131 component_node = node->createNode( "instrumentComponent" );
132 component_node.write_int( "component_id", __related_drumkit_componentID );
133 component_node.write_float( "gain", __gain );
134 }
135 for ( int n = 0; n < m_nMaxLayers; n++ ) {
136 auto pLayer = get_layer( n );
137 if( pLayer != nullptr ) {
138 if( bRecentVersion ) {
139 pLayer->save_to( &component_node, bFull );
140 } else {
141 pLayer->save_to( node, bFull );
142 }
143 }
144 }
145}
146
147QString InstrumentComponent::toQString( const QString& sPrefix, bool bShort ) const {
148 QString s = Base::sPrintIndention;
149 QString sOutput;
150 if ( ! bShort ) {
151 sOutput = QString( "%1[InstrumentComponent]\n" ).arg( sPrefix )
152 .append( QString( "%1%2related_drumkit_componentID: %3\n" ).arg( sPrefix ).arg( s ).arg( __related_drumkit_componentID ) )
153 .append( QString( "%1%2gain: %3\n" ).arg( sPrefix ).arg( s ).arg( __gain ) )
154 .append( QString( "%1%2m_nMaxLayers: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nMaxLayers ) )
155 .append( QString( "%1%2layers:\n" ).arg( sPrefix ).arg( s ) );
156
157 for ( auto ll : __layers ) {
158 if ( ll != nullptr ) {
159 sOutput.append( QString( "%1" ).arg( ll->toQString( sPrefix + s + s, bShort ) ) );
160 }
161 }
162 } else {
163 sOutput = QString( "[InstrumentComponent]" )
164 .append( QString( " related_drumkit_componentID: %1" ).arg( __related_drumkit_componentID ) )
165 .append( QString( ", gain: %1" ).arg( __gain ) )
166 .append( QString( ", m_nMaxLayers: %1" ).arg( m_nMaxLayers ) )
167 .append( QString( ", [layers:" ) );
168
169 for ( auto ll : __layers ) {
170 if ( ll != nullptr ) {
171 sOutput.append( QString( " [%1" ).arg( ll->toQString( sPrefix + s + s, bShort ).replace( "\n", "]" ) ) );
172 }
173 }
174
175 sOutput.append( "]\n" );
176
177 }
178
179 return sOutput;
180}
181
182std::vector<std::shared_ptr<InstrumentLayer>>::iterator InstrumentComponent::begin() {
183 return __layers.begin();
184}
185
186std::vector<std::shared_ptr<InstrumentLayer>>::iterator InstrumentComponent::end() {
187 return __layers.end();
188}
189
190};
191
192/* vim: set softtabstop=4 noexpandtab: */
#define EMPTY_INSTR_ID
Definition Instrument.h:34
#define ERRORLOG(x)
Definition Object.h:242
static QString sPrintIndention
String used to format the debugging string output of some core classes.
Definition Object.h:127
static std::shared_ptr< InstrumentComponent > load_from(XMLNode *pNode, const QString &sDrumkitPath, const License &drumkitLicense=License(), bool bSilent=false)
std::vector< std::shared_ptr< InstrumentLayer > > __layers
std::vector< std::shared_ptr< InstrumentLayer > >::iterator begin()
Iteration.
static int m_nMaxLayers
Maximum number of layers to be used in the Instrument editor.
InstrumentComponent(int related_drumkit_componentID)
static void setMaxLayers(int layers)
int __related_drumkit_componentID
Component ID of the drumkit.
std::vector< std::shared_ptr< InstrumentLayer > >::iterator end()
void set_layer(std::shared_ptr< InstrumentLayer > layer, int idx)
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
std::shared_ptr< InstrumentLayer > get_layer(int idx)
void save_to(XMLNode *node, int component_id, bool bRecentVersion=true, bool bFull=false)
static std::shared_ptr< InstrumentLayer > load_from(XMLNode *pNode, const QString &sDrumkitPath, const License &drumkitLicense=License(), bool bSilent=false)
load an instrument layer from an XMLNode
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
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
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
XMLNode createNode(const QString &name)
create a new XMLNode that has to be appended into de XMLDoc
Definition Xml.cpp:44
void write_int(const QString &node, const int value)
write an integer into a child node
Definition Xml.cpp:265