/[svn]/linuxsampler/trunk/src/drivers/midi/MidiInstrumentMapper.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/drivers/midi/MidiInstrumentMapper.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1763 - (show annotations) (download)
Wed Sep 3 17:18:51 2008 UTC (15 years, 7 months ago) by iliev
File size: 19181 byte(s)
* Optimized the retrieval of the MIDI instrument mappings

1 /***************************************************************************
2 * *
3 * Copyright (C) 2006 - 2007 Christian Schoenebeck *
4 * *
5 * This library is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This library is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this library; if not, write to the Free Software *
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
18 * MA 02111-1307 USA *
19 ***************************************************************************/
20
21 #include "MidiInstrumentMapper.h"
22
23 #include "../../common/global_private.h"
24 #include "../../common/Mutex.h"
25 #include "../../engines/EngineFactory.h"
26 #include "../../engines/Engine.h"
27
28 namespace LinuxSampler {
29
30 // same as entry_t but without 'LoadMode'
31 struct private_entry_t {
32 String EngineName;
33 String InstrumentFile;
34 uint InstrumentIndex;
35 float Volume;
36 String Name;
37 };
38
39 // internal map type (MIDI bank&prog) -> (Engine,File,Index)
40 class MidiInstrumentMap : public std::map<midi_prog_index_t,private_entry_t> {
41 public:
42 String name;
43 };
44
45 // here we store all maps
46 std::map<int,MidiInstrumentMap> midiMaps;
47
48 // for synchronization of midiMaps
49 Mutex midiMapsMutex;
50
51 ListenerList<MidiInstrumentCountListener*> MidiInstrumentMapper::llMidiInstrumentCountListeners;
52 ListenerList<MidiInstrumentInfoListener*> MidiInstrumentMapper::llMidiInstrumentInfoListeners;
53 ListenerList<MidiInstrumentMapCountListener*> MidiInstrumentMapper::llMidiInstrumentMapCountListeners;
54 ListenerList<MidiInstrumentMapInfoListener*> MidiInstrumentMapper::llMidiInstrumentMapInfoListeners;
55 int MidiInstrumentMapper::DefaultMap;
56
57 void MidiInstrumentMapper::AddMidiInstrumentCountListener(MidiInstrumentCountListener* l) {
58 llMidiInstrumentCountListeners.AddListener(l);
59 }
60
61 void MidiInstrumentMapper::RemoveMidiInstrumentCountListener(MidiInstrumentCountListener* l) {
62 llMidiInstrumentCountListeners.RemoveListener(l);
63 }
64
65 void MidiInstrumentMapper::fireMidiInstrumentCountChanged(int MapId, int NewCount) {
66 for (int i = 0; i < llMidiInstrumentCountListeners.GetListenerCount(); i++) {
67 llMidiInstrumentCountListeners.GetListener(i)->MidiInstrumentCountChanged(MapId, NewCount);
68 }
69 }
70
71 void MidiInstrumentMapper::AddMidiInstrumentInfoListener(MidiInstrumentInfoListener* l) {
72 llMidiInstrumentInfoListeners.AddListener(l);
73 }
74
75 void MidiInstrumentMapper::RemoveMidiInstrumentInfoListener(MidiInstrumentInfoListener* l) {
76 llMidiInstrumentInfoListeners.RemoveListener(l);
77 }
78
79 void MidiInstrumentMapper::fireMidiInstrumentInfoChanged(int MapId, int Bank, int Program) {
80 for (int i = 0; i < llMidiInstrumentInfoListeners.GetListenerCount(); i++) {
81 llMidiInstrumentInfoListeners.GetListener(i)->MidiInstrumentInfoChanged(MapId, Bank, Program);
82 }
83 }
84
85 void MidiInstrumentMapper::AddMidiInstrumentMapCountListener(MidiInstrumentMapCountListener* l) {
86 llMidiInstrumentMapCountListeners.AddListener(l);
87 }
88
89 void MidiInstrumentMapper::RemoveMidiInstrumentMapCountListener(MidiInstrumentMapCountListener* l) {
90 llMidiInstrumentMapCountListeners.RemoveListener(l);
91 }
92
93 void MidiInstrumentMapper::fireMidiInstrumentMapCountChanged(int NewCount) {
94 for (int i = 0; i < llMidiInstrumentMapCountListeners.GetListenerCount(); i++) {
95 llMidiInstrumentMapCountListeners.GetListener(i)->MidiInstrumentMapCountChanged(NewCount);
96 }
97 }
98
99 void MidiInstrumentMapper::AddMidiInstrumentMapInfoListener(MidiInstrumentMapInfoListener* l) {
100 llMidiInstrumentMapInfoListeners.AddListener(l);
101 }
102
103 void MidiInstrumentMapper::RemoveMidiInstrumentMapInfoListener(MidiInstrumentMapInfoListener* l) {
104 llMidiInstrumentMapInfoListeners.RemoveListener(l);
105 }
106
107 void MidiInstrumentMapper::fireMidiInstrumentMapInfoChanged(int MapId) {
108 for (int i = 0; i < llMidiInstrumentMapInfoListeners.GetListenerCount(); i++) {
109 llMidiInstrumentMapInfoListeners.GetListener(i)->MidiInstrumentMapInfoChanged(MapId);
110 }
111 }
112
113 void MidiInstrumentMapper::AddOrReplaceEntry(int Map, midi_prog_index_t Index, entry_t Entry, bool bInBackground) throw (Exception) {
114 if (bInBackground) {
115 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d in background\n",
116 Map,
117 Index.midi_bank_msb,Index.midi_bank_lsb,Index.midi_prog,
118 Entry.EngineName.c_str(),Entry.InstrumentFile.c_str(),Entry.InstrumentIndex,
119 Entry.Volume,Entry.LoadMode)
120 );
121 } else {
122 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d\n",
123 Map,
124 Index.midi_bank_msb,Index.midi_bank_lsb,Index.midi_prog,
125 Entry.EngineName.c_str(),Entry.InstrumentFile.c_str(),Entry.InstrumentIndex,
126 Entry.Volume,Entry.LoadMode)
127 );
128 }
129 midiMapsMutex.Lock();
130 if (midiMaps.empty()) {
131 midiMapsMutex.Unlock();
132 throw Exception("There is no MIDI instrument map, you have to add one first.");
133 }
134 midiMapsMutex.Unlock();
135 if (!Entry.InstrumentFile.size())
136 throw Exception("No instrument file name given");
137 // TODO: an easy one - we should check here if given file exists and throw an exception if it doesn't
138 if (Entry.Volume < 0.0)
139 throw Exception("Volume may not be a negative value");
140 Engine* pEngine = EngineFactory::Create(Entry.EngineName);
141 if (!pEngine)
142 throw Exception("No such engine type '"+Entry.EngineName+"'");
143 Entry.EngineName = pEngine->EngineName(); // make sure to use the official engine name
144 if (pEngine->GetInstrumentManager()) {
145 InstrumentManager::instrument_id_t id;
146 id.FileName = Entry.InstrumentFile;
147 id.Index = Entry.InstrumentIndex;
148 if (Entry.LoadMode != DONTCARE) {
149 if (bInBackground)
150 pEngine->GetInstrumentManager()->SetModeInBackground(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode));
151 else
152 pEngine->GetInstrumentManager()->SetMode(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode));
153 }
154 } else {
155 dmsg(1,("WARNING: no InstrumentManager for engine '%s'\n",Entry.EngineName.c_str()));
156 }
157 private_entry_t privateEntry;
158 privateEntry.EngineName = Entry.EngineName;
159 privateEntry.InstrumentFile = Entry.InstrumentFile;
160 privateEntry.InstrumentIndex = Entry.InstrumentIndex;
161 privateEntry.Volume = Entry.Volume;
162 privateEntry.Name = Entry.Name;
163
164 bool Replaced = false;
165 int InstrCount = 0;
166
167 midiMapsMutex.Lock();
168 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
169 if (iterMap != midiMaps.end()) { // map found
170 Replaced = (iterMap->second.find(Index) != iterMap->second.end());
171 iterMap->second[Index] = privateEntry;
172 InstrCount = iterMap->second.size();
173 } else { // no such map
174 midiMapsMutex.Unlock();
175 EngineFactory::Destroy(pEngine);
176 throw Exception("There is no MIDI instrument map " + ToString(Map));
177 }
178 midiMapsMutex.Unlock();
179 EngineFactory::Destroy(pEngine);
180
181 if (Replaced) {
182 int Bank = (int(Index.midi_bank_msb) << 7) | int(Index.midi_bank_lsb);
183 fireMidiInstrumentInfoChanged(Map, Bank, Index.midi_prog);
184 } else {
185 fireMidiInstrumentCountChanged(Map, InstrCount);
186 }
187 }
188
189 void MidiInstrumentMapper::SetLoadMode(entry_t* pEntry) {
190 Engine* pEngine = EngineFactory::Create(pEntry->EngineName);
191 if (!pEngine) { // invalid mapping
192 throw Exception("Invalid mapping");
193 }
194
195 InstrumentManager* pManager = pEngine->GetInstrumentManager();
196 if (pManager) { // engine provides an InstrumentManager
197 InstrumentManager::instrument_id_t id;
198 id.FileName = pEntry->InstrumentFile;
199 id.Index = pEntry->InstrumentIndex;
200 pEntry->LoadMode = static_cast<mode_t>(pManager->GetMode(id));
201 } else { // engine does not provide an InstrumentManager
202 // use default value
203 pEntry->LoadMode = ON_DEMAND;
204 }
205
206 EngineFactory::Destroy(pEngine);
207 }
208
209 MidiInstrumentMapper::entry_t MidiInstrumentMapper::GetEntry(int Map, uint MidiBank, uint MidiProg) {
210 midiMapsMutex.Lock();
211 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
212 if (iterMap == midiMaps.end()) { // no such map
213 midiMapsMutex.Unlock();
214 throw Exception("There is no MIDI instrument map " + ToString(Map));
215 }
216
217 midi_prog_index_t idx;
218 idx.midi_bank_msb = (MidiBank >> 7) & 0x7f;
219 idx.midi_bank_lsb = MidiBank & 0x7f;
220 idx.midi_prog = MidiProg;
221
222 std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.find(idx);
223 if (iterEntry == iterMap->second.end()) {
224 midiMapsMutex.Unlock();
225 throw Exception("There is no map entry with that index");
226 }
227
228 entry_t entry;
229 entry.EngineName = iterEntry->second.EngineName;
230 entry.InstrumentFile = iterEntry->second.InstrumentFile;
231 entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
232 entry.Volume = iterEntry->second.Volume;
233 entry.Name = iterEntry->second.Name;
234
235 try {
236 SetLoadMode(&entry);
237 } catch(Exception e) {
238 midiMapsMutex.Unlock();
239 throw e;
240 }
241
242 midiMapsMutex.Unlock();
243
244 return entry;
245 }
246
247 void MidiInstrumentMapper::RemoveEntry(int Map, midi_prog_index_t Index) {
248 int InstrCount = -1;
249
250 midiMapsMutex.Lock();
251 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
252 if (iterMap != midiMaps.end()) { // map found
253 iterMap->second.erase(Index); // remove entry
254 InstrCount = iterMap->second.size();
255 }
256 midiMapsMutex.Unlock();
257
258 if (InstrCount != -1) {
259 fireMidiInstrumentCountChanged(Map, InstrCount);
260 }
261 }
262
263 void MidiInstrumentMapper::RemoveAllEntries(int Map) {
264 int InstrCount = -1;
265
266 midiMapsMutex.Lock();
267 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
268 if (iterMap != midiMaps.end()) { // map found
269 iterMap->second.clear(); // clear that map
270 InstrCount = 0;
271 }
272 midiMapsMutex.Unlock();
273
274 if (InstrCount != -1) {
275 fireMidiInstrumentCountChanged(Map, InstrCount);
276 }
277 }
278
279 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> MidiInstrumentMapper::Entries(int Map) throw (Exception) {
280 std::map<midi_prog_index_t,entry_t> result;
281
282 // copy the internal map first
283 midiMapsMutex.Lock();
284 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
285 if (iterMap == midiMaps.end()) { // no such map
286 midiMapsMutex.Unlock();
287 throw Exception("There is no MIDI instrument map " + ToString(Map));
288 }
289 for (std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.begin();
290 iterEntry != iterMap->second.end(); iterEntry++)
291 {
292 entry_t entry;
293 entry.EngineName = iterEntry->second.EngineName;
294 entry.InstrumentFile = iterEntry->second.InstrumentFile;
295 entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
296 entry.Volume = iterEntry->second.Volume;
297 entry.Name = iterEntry->second.Name;
298 result[iterEntry->first] = entry;
299 }
300 midiMapsMutex.Unlock();
301
302 // complete it with current LoadMode of each entry
303 for (std::map<midi_prog_index_t,entry_t>::iterator iter = result.begin();
304 iter != result.end(); iter++)
305 {
306 try {
307 SetLoadMode(&(iter->second));
308 } catch(Exception e) {
309 RemoveEntry(Map, iter->first);
310 result.erase(iter);
311 }
312 }
313 return result;
314 }
315
316 std::vector<int> MidiInstrumentMapper::Maps() {
317 std::vector<int> result;
318 midiMapsMutex.Lock();
319 for (std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.begin();
320 iterMap != midiMaps.end(); iterMap++)
321 {
322 result.push_back(iterMap->first);
323 }
324 midiMapsMutex.Unlock();
325 return result;
326 }
327
328 int MidiInstrumentMapper::GetMapCount() {
329 midiMapsMutex.Lock();
330 int i = midiMaps.size();
331 midiMapsMutex.Unlock();
332 return i;
333 }
334
335 int MidiInstrumentMapper::GetInstrumentCount(int Map) {
336 midiMapsMutex.Lock();
337 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
338 if (iterMap == midiMaps.end()) { // no such map
339 midiMapsMutex.Unlock();
340 throw Exception("There is no MIDI instrument map " + ToString(Map));
341 }
342
343 int i = iterMap->second.size();
344 midiMapsMutex.Unlock();
345 return i;
346 }
347
348 int MidiInstrumentMapper::GetInstrumentCount() {
349 int count = 0;
350
351 midiMapsMutex.Lock();
352 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.begin();
353 for (;iterMap != midiMaps.end(); iterMap++) {
354 count += iterMap->second.size();
355 }
356 midiMapsMutex.Unlock();
357
358 return count;
359 }
360
361 int MidiInstrumentMapper::AddMap(String MapName) throw (Exception) {
362 int ID;
363 midiMapsMutex.Lock();
364 if (midiMaps.empty()) ID = 0;
365 else {
366 // get the highest existing map ID
367 uint lastIndex = (--(midiMaps.end()))->first;
368 // check if we reached the index limit
369 if (lastIndex + 1 < lastIndex) {
370 // search for an unoccupied map ID starting from 0
371 for (uint i = 0; i < lastIndex; i++) {
372 if (midiMaps.find(i) != midiMaps.end()) continue;
373 // we found an unused ID, so insert the new map there
374 ID = i;
375 goto __create_map;
376 }
377 throw Exception("Internal error: could not find unoccupied MIDI instrument map ID.");
378 }
379 ID = lastIndex + 1;
380 }
381 __create_map:
382 midiMaps[ID].name = MapName;
383
384 fireMidiInstrumentMapCountChanged(Maps().size());
385 // If there were no maps until now we must set a default map.
386 if (midiMaps.size() == 1) SetDefaultMap(ID);
387 midiMapsMutex.Unlock();
388
389 return ID;
390 }
391
392 String MidiInstrumentMapper::MapName(int Map) throw (Exception) {
393 String result;
394 midiMapsMutex.Lock();
395 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
396 if (iterMap == midiMaps.end()) {
397 midiMapsMutex.Unlock();
398 throw Exception("There is no MIDI instrument map " + ToString(Map));
399 }
400 result = iterMap->second.name;
401 midiMapsMutex.Unlock();
402 return result;
403 }
404
405 void MidiInstrumentMapper::RenameMap(int Map, String NewName) throw (Exception) {
406 midiMapsMutex.Lock();
407 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
408 if (iterMap == midiMaps.end()) {
409 midiMapsMutex.Unlock();
410 throw Exception("There is no MIDI instrument map " + ToString(Map));
411 }
412 iterMap->second.name = NewName;
413 midiMapsMutex.Unlock();
414 fireMidiInstrumentMapInfoChanged(Map);
415 }
416
417 void MidiInstrumentMapper::RemoveMap(int Map) {
418 midiMapsMutex.Lock();
419 midiMaps.erase(Map);
420 if(Map == GetDefaultMap()) {
421 SetDefaultMap(midiMaps.empty() ? -1 : (*(midiMaps.begin())).first);
422 }
423 fireMidiInstrumentMapCountChanged(Maps().size());
424 midiMapsMutex.Unlock();
425 }
426
427 void MidiInstrumentMapper::RemoveAllMaps() {
428 midiMapsMutex.Lock();
429 midiMaps.clear();
430 SetDefaultMap(-1);
431 fireMidiInstrumentMapCountChanged(Maps().size());
432 midiMapsMutex.Unlock();
433 }
434
435 int MidiInstrumentMapper::GetDefaultMap() {
436 midiMapsMutex.Lock();
437 int i = DefaultMap;
438 midiMapsMutex.Unlock();
439 return i;
440 }
441
442 void MidiInstrumentMapper::SetDefaultMap(int MapId) {
443 midiMapsMutex.Lock();
444 DefaultMap = MapId;
445 midiMapsMutex.Unlock();
446
447 if (MapId != -1) fireMidiInstrumentMapInfoChanged(MapId);
448 }
449
450 optional<MidiInstrumentMapper::entry_t> MidiInstrumentMapper::GetEntry(int Map, midi_prog_index_t Index) {
451 optional<entry_t> result;
452 midiMapsMutex.Lock();
453 std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
454 if (iterMap != midiMaps.end()) { // map found
455 std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.find(Index);
456 if (iterEntry != iterMap->second.end()) {
457 entry_t entry;
458 entry.EngineName = iterEntry->second.EngineName;
459 entry.InstrumentFile = iterEntry->second.InstrumentFile;
460 entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
461 entry.Volume = iterEntry->second.Volume;
462 //TODO: for now we skip the LoadMode and Name entry here, since we don't need it in the MidiInputPort
463 result = entry;
464 }
465 }
466 midiMapsMutex.Unlock();
467 return result;
468 }
469
470 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC