/[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 1130 - (hide annotations) (download)
Sun Mar 25 18:59:14 2007 UTC (17 years, 1 month ago) by iliev
File size: 15934 byte(s)
* Implemented new, improved notification system

1 schoenebeck 947 /***************************************************************************
2     * *
3 schoenebeck 1040 * Copyright (C) 2006 - 2007 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     #include "../../common/Mutex.h"
24     #include "../../engines/EngineFactory.h"
25     #include "../../engines/Engine.h"
26    
27     namespace LinuxSampler {
28    
29     // same as entry_t but without 'LoadMode'
30     struct private_entry_t {
31     String EngineName;
32     String InstrumentFile;
33     uint InstrumentIndex;
34 schoenebeck 958 float Volume;
35 schoenebeck 947 String Name;
36     };
37    
38 schoenebeck 973 // internal map type (MIDI bank&prog) -> (Engine,File,Index)
39     class MidiInstrumentMap : public std::map<midi_prog_index_t,private_entry_t> {
40     public:
41     String name;
42     };
43 schoenebeck 947
44 schoenebeck 973 // here we store all maps
45     std::map<int,MidiInstrumentMap> midiMaps;
46 schoenebeck 947
47 schoenebeck 973 // for synchronization of midiMaps
48     Mutex midiMapsMutex;
49 schoenebeck 947
50 schoenebeck 973
51 iliev 1130 ListenerList<MidiInstrumentCountListener*> MidiInstrumentMapper::llMidiInstrumentCountListeners;
52     ListenerList<MidiInstrumentInfoListener*> MidiInstrumentMapper::llMidiInstrumentInfoListeners;
53     ListenerList<MidiInstrumentMapCountListener*> MidiInstrumentMapper::llMidiInstrumentMapCountListeners;
54     ListenerList<MidiInstrumentMapInfoListener*> MidiInstrumentMapper::llMidiInstrumentMapInfoListeners;
55    
56     void MidiInstrumentMapper::AddMidiInstrumentCountListener(MidiInstrumentCountListener* l) {
57     llMidiInstrumentCountListeners.AddListener(l);
58     }
59    
60     void MidiInstrumentMapper::RemoveMidiInstrumentCountListener(MidiInstrumentCountListener* l) {
61     llMidiInstrumentCountListeners.RemoveListener(l);
62     }
63    
64     void MidiInstrumentMapper::fireMidiInstrumentCountChanged(int MapId, int NewCount) {
65     for (int i = 0; i < llMidiInstrumentCountListeners.GetListenerCount(); i++) {
66     llMidiInstrumentCountListeners.GetListener(i)->MidiInstrumentCountChanged(MapId, NewCount);
67     }
68     }
69    
70     void MidiInstrumentMapper::AddMidiInstrumentInfoListener(MidiInstrumentInfoListener* l) {
71     llMidiInstrumentInfoListeners.AddListener(l);
72     }
73    
74     void MidiInstrumentMapper::RemoveMidiInstrumentInfoListener(MidiInstrumentInfoListener* l) {
75     llMidiInstrumentInfoListeners.RemoveListener(l);
76     }
77    
78     void MidiInstrumentMapper::fireMidiInstrumentInfoChanged(int MapId, int Bank, int Program) {
79     for (int i = 0; i < llMidiInstrumentInfoListeners.GetListenerCount(); i++) {
80     llMidiInstrumentInfoListeners.GetListener(i)->MidiInstrumentInfoChanged(MapId, Bank, Program);
81     }
82     }
83    
84     void MidiInstrumentMapper::AddMidiInstrumentMapCountListener(MidiInstrumentMapCountListener* l) {
85     llMidiInstrumentMapCountListeners.AddListener(l);
86     }
87    
88     void MidiInstrumentMapper::RemoveMidiInstrumentMapCountListener(MidiInstrumentMapCountListener* l) {
89     llMidiInstrumentMapCountListeners.RemoveListener(l);
90     }
91    
92     void MidiInstrumentMapper::fireMidiInstrumentMapCountChanged(int NewCount) {
93     for (int i = 0; i < llMidiInstrumentMapCountListeners.GetListenerCount(); i++) {
94     llMidiInstrumentMapCountListeners.GetListener(i)->MidiInstrumentMapCountChanged(NewCount);
95     }
96     }
97    
98     void MidiInstrumentMapper::AddMidiInstrumentMapInfoListener(MidiInstrumentMapInfoListener* l) {
99     llMidiInstrumentMapInfoListeners.AddListener(l);
100     }
101    
102     void MidiInstrumentMapper::RemoveMidiInstrumentMapInfoListener(MidiInstrumentMapInfoListener* l) {
103     llMidiInstrumentMapInfoListeners.RemoveListener(l);
104     }
105    
106     void MidiInstrumentMapper::fireMidiInstrumentMapInfoChanged(int MapId) {
107     for (int i = 0; i < llMidiInstrumentMapInfoListeners.GetListenerCount(); i++) {
108     llMidiInstrumentMapInfoListeners.GetListener(i)->MidiInstrumentMapInfoChanged(MapId);
109     }
110     }
111    
112 schoenebeck 973 void MidiInstrumentMapper::AddOrReplaceEntry(int Map, midi_prog_index_t Index, entry_t Entry, bool bInBackground) throw (Exception) {
113 schoenebeck 947 if (bInBackground) {
114 schoenebeck 973 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d in background\n",
115     Map,
116 schoenebeck 947 Index.midi_bank_msb,Index.midi_bank_lsb,Index.midi_prog,
117     Entry.EngineName.c_str(),Entry.InstrumentFile.c_str(),Entry.InstrumentIndex,
118     Entry.Volume,Entry.LoadMode)
119     );
120     } else {
121 schoenebeck 973 dmsg(3,("MidiInstrumentMapper: updating mapping %d (%d,%d,%d) -> ('%s','%s',%d) with vol=%f, mode=%d\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     }
128 schoenebeck 973 midiMapsMutex.Lock();
129     if (midiMaps.empty()) {
130     midiMapsMutex.Unlock();
131     throw Exception("There is no MIDI instrument map, you have to add one first.");
132     }
133     midiMapsMutex.Unlock();
134 schoenebeck 970 if (!Entry.InstrumentFile.size())
135     throw Exception("No instrument file name given");
136 schoenebeck 1040 // TODO: an easy one - we should check here if given file exists and throw an exception if it doesn't
137 schoenebeck 947 if (Entry.Volume < 0.0)
138     throw Exception("Volume may not be a negative value");
139     Engine* pEngine = EngineFactory::Create(Entry.EngineName);
140     if (!pEngine)
141     throw Exception("No such engine type '"+Entry.EngineName+"'");
142     Entry.EngineName = pEngine->EngineName(); // make sure to use the official engine name
143     if (pEngine->GetInstrumentManager()) {
144     InstrumentManager::instrument_id_t id;
145     id.FileName = Entry.InstrumentFile;
146     id.Index = Entry.InstrumentIndex;
147     if (Entry.LoadMode != VOID) {
148     if (bInBackground)
149     pEngine->GetInstrumentManager()->SetModeInBackground(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode));
150     else
151     pEngine->GetInstrumentManager()->SetMode(id, static_cast<InstrumentManager::mode_t>(Entry.LoadMode));
152     }
153     } else {
154     dmsg(1,("WARNING: no InstrumentManager for engine '%s'\n",Entry.EngineName.c_str()));
155     }
156     private_entry_t privateEntry;
157     privateEntry.EngineName = Entry.EngineName;
158     privateEntry.InstrumentFile = Entry.InstrumentFile;
159     privateEntry.InstrumentIndex = Entry.InstrumentIndex;
160 schoenebeck 958 privateEntry.Volume = Entry.Volume;
161 schoenebeck 947 privateEntry.Name = Entry.Name;
162 iliev 981
163     bool Replaced = false;
164     int InstrCount = 0;
165    
166 schoenebeck 973 midiMapsMutex.Lock();
167     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
168     if (iterMap != midiMaps.end()) { // map found
169 iliev 981 Replaced = (iterMap->second.find(Index) != iterMap->second.end());
170 schoenebeck 973 iterMap->second[Index] = privateEntry;
171 iliev 981 InstrCount = iterMap->second.size();
172 schoenebeck 973 } else { // no such map
173     midiMapsMutex.Unlock();
174     EngineFactory::Destroy(pEngine);
175     throw Exception("There is no MIDI instrument map " + ToString(Map));
176     }
177     midiMapsMutex.Unlock();
178 schoenebeck 947 EngineFactory::Destroy(pEngine);
179 iliev 981
180     if (Replaced) {
181     int Bank = (int(Index.midi_bank_msb) << 7) & int(Index.midi_bank_lsb);
182 iliev 1130 fireMidiInstrumentInfoChanged(Map, Bank, Index.midi_prog);
183 iliev 981 } else {
184 iliev 1130 fireMidiInstrumentCountChanged(Map, InstrCount);
185 iliev 981 }
186 schoenebeck 947 }
187    
188 schoenebeck 973 void MidiInstrumentMapper::RemoveEntry(int Map, midi_prog_index_t Index) {
189 iliev 981 int InstrCount = -1;
190    
191 schoenebeck 973 midiMapsMutex.Lock();
192     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
193     if (iterMap != midiMaps.end()) { // map found
194     iterMap->second.erase(Index); // remove entry
195 iliev 981 InstrCount = iterMap->second.size();
196 schoenebeck 973 }
197     midiMapsMutex.Unlock();
198 iliev 981
199     if (InstrCount != -1) {
200 iliev 1130 fireMidiInstrumentCountChanged(Map, InstrCount);
201 iliev 981 }
202 schoenebeck 947 }
203    
204 schoenebeck 973 void MidiInstrumentMapper::RemoveAllEntries(int Map) {
205 iliev 981 int InstrCount = -1;
206    
207 schoenebeck 973 midiMapsMutex.Lock();
208     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
209     if (iterMap != midiMaps.end()) { // map found
210     iterMap->second.clear(); // clear that map
211 iliev 981 InstrCount = 0;
212 schoenebeck 973 }
213     midiMapsMutex.Unlock();
214 iliev 981
215     if (InstrCount != -1) {
216 iliev 1130 fireMidiInstrumentCountChanged(Map, InstrCount);
217 iliev 981 }
218 schoenebeck 947 }
219    
220 schoenebeck 973 std::map<midi_prog_index_t,MidiInstrumentMapper::entry_t> MidiInstrumentMapper::Entries(int Map) throw (Exception) {
221 schoenebeck 947 std::map<midi_prog_index_t,entry_t> result;
222 schoenebeck 973
223 schoenebeck 947 // copy the internal map first
224 schoenebeck 973 midiMapsMutex.Lock();
225     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
226     if (iterMap == midiMaps.end()) { // no such map
227     midiMapsMutex.Unlock();
228     throw Exception("There is no MIDI instrument map " + ToString(Map));
229     }
230     for (std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.begin();
231     iterEntry != iterMap->second.end(); iterEntry++)
232 schoenebeck 947 {
233     entry_t entry;
234 schoenebeck 973 entry.EngineName = iterEntry->second.EngineName;
235     entry.InstrumentFile = iterEntry->second.InstrumentFile;
236     entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
237     entry.Volume = iterEntry->second.Volume;
238     entry.Name = iterEntry->second.Name;
239     result[iterEntry->first] = entry;
240 schoenebeck 947 }
241 schoenebeck 973 midiMapsMutex.Unlock();
242    
243 schoenebeck 958 // complete it with current LoadMode of each entry
244 schoenebeck 947 for (std::map<midi_prog_index_t,entry_t>::iterator iter = result.begin();
245     iter != result.end(); iter++)
246     {
247     entry_t& entry = iter->second;
248     Engine* pEngine = EngineFactory::Create(entry.EngineName);
249     if (!pEngine) { // invalid mapping
250 schoenebeck 973 RemoveEntry(Map, iter->first);
251 schoenebeck 947 result.erase(iter);
252     continue;
253     }
254     InstrumentManager* pManager = pEngine->GetInstrumentManager();
255     if (pManager) { // engine provides an InstrumentManager
256     InstrumentManager::instrument_id_t id;
257     id.FileName = entry.InstrumentFile;
258     id.Index = entry.InstrumentIndex;
259     entry.LoadMode = static_cast<mode_t>(pManager->GetMode(id));
260     } else { // engine does not provide an InstrumentManager
261 schoenebeck 958 // use default value
262 schoenebeck 947 entry.LoadMode = ON_DEMAND;
263     }
264     EngineFactory::Destroy(pEngine);
265     }
266     return result;
267     }
268    
269 schoenebeck 973 std::vector<int> MidiInstrumentMapper::Maps() {
270     std::vector<int> result;
271     midiMapsMutex.Lock();
272     for (std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.begin();
273     iterMap != midiMaps.end(); iterMap++)
274     {
275     result.push_back(iterMap->first);
276     }
277     midiMapsMutex.Unlock();
278     return result;
279     }
280    
281     int MidiInstrumentMapper::AddMap(String MapName) throw (Exception) {
282     int ID;
283     midiMapsMutex.Lock();
284     if (midiMaps.empty()) ID = 0;
285     else {
286     // get the highest existing map ID
287     uint lastIndex = (--(midiMaps.end()))->first;
288     // check if we reached the index limit
289     if (lastIndex + 1 < lastIndex) {
290     // search for an unoccupied map ID starting from 0
291     for (uint i = 0; i < lastIndex; i++) {
292     if (midiMaps.find(i) != midiMaps.end()) continue;
293     // we found an unused ID, so insert the new map there
294     ID = i;
295     goto __create_map;
296     }
297     throw Exception("Internal error: could not find unoccupied MIDI instrument map ID.");
298     }
299 iliev 976 ID = lastIndex + 1;
300 schoenebeck 973 }
301     __create_map:
302     midiMaps[ID].name = MapName;
303     midiMapsMutex.Unlock();
304 iliev 981
305 iliev 1130 fireMidiInstrumentMapCountChanged(Maps().size());
306 schoenebeck 973 return ID;
307     }
308    
309     String MidiInstrumentMapper::MapName(int Map) throw (Exception) {
310     String result;
311     midiMapsMutex.Lock();
312     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
313     if (iterMap == midiMaps.end()) {
314     midiMapsMutex.Unlock();
315     throw Exception("There is no MIDI instrument map " + ToString(Map));
316     }
317     result = iterMap->second.name;
318     midiMapsMutex.Unlock();
319     return result;
320     }
321    
322     void MidiInstrumentMapper::RenameMap(int Map, String NewName) throw (Exception) {
323     midiMapsMutex.Lock();
324     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
325     if (iterMap == midiMaps.end()) {
326     midiMapsMutex.Unlock();
327     throw Exception("There is no MIDI instrument map " + ToString(Map));
328     }
329     iterMap->second.name = NewName;
330     midiMapsMutex.Unlock();
331 iliev 1130 fireMidiInstrumentMapInfoChanged(Map);
332 schoenebeck 973 }
333    
334     void MidiInstrumentMapper::RemoveMap(int Map) {
335     midiMapsMutex.Lock();
336     midiMaps.erase(Map);
337     midiMapsMutex.Unlock();
338 iliev 1130 fireMidiInstrumentMapCountChanged(Maps().size());
339 schoenebeck 973 }
340    
341     void MidiInstrumentMapper::RemoveAllMaps() {
342     midiMapsMutex.Lock();
343     midiMaps.clear();
344     midiMapsMutex.Unlock();
345 iliev 1130 fireMidiInstrumentMapCountChanged(Maps().size());
346 schoenebeck 973 }
347    
348     optional<MidiInstrumentMapper::entry_t> MidiInstrumentMapper::GetEntry(int Map, midi_prog_index_t Index) {
349 schoenebeck 947 optional<entry_t> result;
350 schoenebeck 973 midiMapsMutex.Lock();
351     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
352     if (iterMap != midiMaps.end()) { // map found
353     std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.find(Index);
354     if (iterEntry != iterMap->second.end()) {
355     entry_t entry;
356     entry.EngineName = iterEntry->second.EngineName;
357     entry.InstrumentFile = iterEntry->second.InstrumentFile;
358     entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
359     entry.Volume = iterEntry->second.Volume;
360     //TODO: for now we skip the LoadMode and Name entry here, since we don't need it in the MidiInputPort
361     result = entry;
362     }
363 schoenebeck 947 }
364 schoenebeck 973 midiMapsMutex.Unlock();
365 schoenebeck 947 return result;
366     }
367    
368     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC