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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3705 - (hide annotations) (download)
Wed Jan 8 20:26:53 2020 UTC (4 years, 3 months ago) by schoenebeck
File size: 18908 byte(s)
Fixed compiler warnings about exception handling:

Use re-throw semantic instead of copying exception objects.

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

  ViewVC Help
Powered by ViewVC