1 /*
2  * Hydrogen
3  * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.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, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22 
23 #include <hydrogen/basics/instrument_list.h>
24 
25 #include <hydrogen/helpers/xml.h>
26 #include <hydrogen/basics/instrument.h>
27 
28 #include <set>
29 
30 namespace H2Core
31 {
32 
33 const char* InstrumentList::__class_name = "InstrumentList";
34 
InstrumentList()35 InstrumentList::InstrumentList() : Object( __class_name )
36 {
37 }
38 
InstrumentList(InstrumentList * other)39 InstrumentList::InstrumentList( InstrumentList* other ) : Object( __class_name )
40 {
41 	assert( __instruments.size() == 0 );
42 	for ( int i=0; i<other->size(); i++ ) {
43 		( *this ) << ( new Instrument( ( *other )[i] ) );
44 	}
45 }
46 
~InstrumentList()47 InstrumentList::~InstrumentList()
48 {
49 	for ( int i = 0; i < __instruments.size(); ++i ) {
50 		delete __instruments[i];
51 	}
52 }
53 
load_samples()54 void InstrumentList::load_samples()
55 {
56 	for( int i=0; i<__instruments.size(); i++ ) {
57 		__instruments[i]->load_samples();
58 	}
59 }
60 
unload_samples()61 void InstrumentList::unload_samples()
62 {
63 	for( int i=0; i<__instruments.size(); i++ ) {
64 		__instruments[i]->unload_samples();
65 	}
66 }
67 
load_from(XMLNode * node,const QString & dk_path,const QString & dk_name)68 InstrumentList* InstrumentList::load_from( XMLNode* node, const QString& dk_path, const QString& dk_name )
69 {
70 	InstrumentList* instruments = new InstrumentList();
71 	XMLNode instrument_node = node->firstChildElement( "instrument" );
72 	int count = 0;
73 	while ( !instrument_node.isNull() ) {
74 		count++;
75 		if ( count > MAX_INSTRUMENTS ) {
76 			ERRORLOG( QString( "instrument count >= %2, stop reading instruments" ).arg( MAX_INSTRUMENTS ) );
77 			break;
78 		}
79 		Instrument* instrument = Instrument::load_from( &instrument_node, dk_path, dk_name );
80 		if( instrument ) {
81 			( *instruments ) << instrument;
82 		} else {
83 			ERRORLOG( QString( "Empty ID for instrument %1. The drumkit is corrupted. Skipping instrument" ).arg( count ) );
84 			count--;
85 		}
86 		instrument_node = instrument_node.nextSiblingElement( "instrument" );
87 	}
88 	return instruments;
89 }
90 
save_to(XMLNode * node,int component_id)91 void InstrumentList::save_to( XMLNode* node, int component_id )
92 {
93 	XMLNode instruments_node = node->createNode( "instrumentList" );
94 	for ( int i = 0; i < size(); i++ ) {
95 		( *this )[i]->save_to( &instruments_node, component_id );
96 	}
97 }
98 
operator <<(Instrument * instrument)99 void InstrumentList::operator<<( Instrument* instrument )
100 {
101 	// do nothing if already in __instruments
102 	for( int i=0; i<__instruments.size(); i++ ) {
103 		if( __instruments[i]==instrument ) return;
104 	}
105 	__instruments.push_back( instrument );
106 }
107 
add(Instrument * instrument)108 void InstrumentList::add( Instrument* instrument )
109 {
110 	// do nothing if already in __instruments
111 	for( int i=0; i<__instruments.size(); i++ ) {
112 		if( __instruments[i]==instrument ) return;
113 	}
114 	__instruments.push_back( instrument );
115 }
116 
insert(int idx,Instrument * instrument)117 void InstrumentList::insert( int idx, Instrument* instrument )
118 {
119 	// do nothing if already in __instruments
120 	for( int i=0; i<__instruments.size(); i++ ) {
121 		if( __instruments[i]==instrument ) return;
122 	}
123 	__instruments.insert( __instruments.begin() + idx, instrument );
124 }
125 
operator [](int idx)126 Instrument* InstrumentList::operator[]( int idx )
127 {
128 	if ( idx < 0 || idx >= __instruments.size() ) {
129 		ERRORLOG( QString( "idx %1 out of [0;%2]" ).arg( idx ).arg( size() ) );
130 		return nullptr;
131 	}
132 	assert( idx >= 0 && idx < __instruments.size() );
133 	return __instruments[idx];
134 }
135 
is_valid_index(int idx) const136 bool InstrumentList::is_valid_index( int idx ) const
137 {
138 	bool is_valid_index = true;
139 
140 	if ( idx < 0 || idx >= __instruments.size() ) {
141 		is_valid_index = false;
142 	}
143 
144 	return is_valid_index;
145 }
146 
get(int idx)147 Instrument* InstrumentList::get( int idx )
148 {
149 	if ( !is_valid_index( idx ) ) {
150 		ERRORLOG( QString( "idx %1 out of [0;%2]" ).arg( idx ).arg( size() ) );
151 		return nullptr;
152 	}
153 	assert( idx >= 0 && idx < __instruments.size() );
154 	return __instruments[idx];
155 }
156 
index(Instrument * instr)157 int InstrumentList::index( Instrument* instr )
158 {
159 	for( int i=0; i<__instruments.size(); i++ ) {
160 		if ( __instruments[i]==instr ) return i;
161 	}
162 	return -1;
163 }
164 
find(const int id)165 Instrument*  InstrumentList::find( const int id )
166 {
167 	for( int i=0; i<__instruments.size(); i++ ) {
168 		if ( __instruments[i]->get_id()==id ) return __instruments[i];
169 	}
170 	return nullptr;
171 }
172 
find(const QString & name)173 Instrument*  InstrumentList::find( const QString& name )
174 {
175 	for( int i=0; i<__instruments.size(); i++ ) {
176 		if ( __instruments[i]->get_name()==name ) return __instruments[i];
177 	}
178 	return nullptr;
179 }
180 
findMidiNote(const int note)181 Instrument*  InstrumentList::findMidiNote( const int note )
182 {
183 	for( int i=0; i<__instruments.size(); i++ ) {
184 		if ( __instruments[i]->get_midi_out_note()==note ) return __instruments[i];
185 	}
186 	return nullptr;
187 }
188 
del(int idx)189 Instrument* InstrumentList::del( int idx )
190 {
191 	assert( idx >= 0 && idx < __instruments.size() );
192 	Instrument* instrument = __instruments[idx];
193 	__instruments.erase( __instruments.begin() + idx );
194 	return instrument;
195 }
196 
del(Instrument * instrument)197 Instrument* InstrumentList::del( Instrument* instrument )
198 {
199 	for( int i=0; i<__instruments.size(); i++ ) {
200 		if( __instruments[i]==instrument ) {
201 			__instruments.erase( __instruments.begin() + i );
202 			return instrument;
203 		}
204 	}
205 	return nullptr;
206 }
207 
swap(int idx_a,int idx_b)208 void InstrumentList::swap( int idx_a, int idx_b )
209 {
210 	assert( idx_a >= 0 && idx_a < __instruments.size() );
211 	assert( idx_b >= 0 && idx_b < __instruments.size() );
212 	if( idx_a == idx_b ) return;
213 	//DEBUGLOG(QString("===>> SWAP  %1 %2").arg(idx_a).arg(idx_b) );
214 	Instrument* tmp = __instruments[idx_a];
215 	__instruments[idx_a] = __instruments[idx_b];
216 	__instruments[idx_b] = tmp;
217 }
218 
move(int idx_a,int idx_b)219 void InstrumentList::move( int idx_a, int idx_b )
220 {
221 	assert( idx_a >= 0 && idx_a < __instruments.size() );
222 	assert( idx_b >= 0 && idx_b < __instruments.size() );
223 	if( idx_a == idx_b ) return;
224 	//DEBUGLOG(QString("===>> MOVE  %1 %2").arg(idx_a).arg(idx_b) );
225 	Instrument* tmp = __instruments[idx_a];
226 	__instruments.erase( __instruments.begin() + idx_a );
227 	__instruments.insert( __instruments.begin() + idx_b, tmp );
228 }
229 
fix_issue_307()230 void InstrumentList::fix_issue_307()
231 {
232 	if ( has_all_midi_notes_same() ) {
233 		WARNINGLOG( "Same MIDI note assigned to every instrument. Assigning default values." );
234 		set_default_midi_out_notes();
235 	}
236 }
237 
has_all_midi_notes_same() const238 bool InstrumentList::has_all_midi_notes_same() const
239 {
240 	if (__instruments.size() < 2) {
241 		return false;
242 	}
243 
244 	std::set<int> notes;
245 	for( int i=0; i<__instruments.size(); i++ ) {
246 		auto instr = __instruments[i];
247 		notes.insert( instr->get_midi_out_note() );
248 	}
249 	return notes.size() == 1;
250 }
251 
set_default_midi_out_notes()252 void InstrumentList::set_default_midi_out_notes()
253 {
254 	for( int i=0; i<__instruments.size(); i++ ) {
255 		__instruments[i]->set_midi_out_note( i + 36 );
256 	}
257 }
258 
259 };
260 
261 /* vim: set softtabstop=4 noexpandtab: */
262