/[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 1827 - (show annotations) (download)
Mon Jan 26 17:27:29 2009 UTC (15 years, 2 months ago) by iliev
File size: 19286 byte(s)
* fixed termination caused by uncaught exception when adding MIDI
  instrument with PERSISTENT load mode

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

  ViewVC Help
Powered by ViewVC