/[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 1135 - (hide annotations) (download)
Thu Mar 29 09:40:45 2007 UTC (12 years, 11 months ago) by iliev
File size: 16828 byte(s)
* Added new LSCP command - SET FX_SEND NAME
* The default map is now the first available map

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 iliev 1130 ListenerList<MidiInstrumentCountListener*> MidiInstrumentMapper::llMidiInstrumentCountListeners;
51     ListenerList<MidiInstrumentInfoListener*> MidiInstrumentMapper::llMidiInstrumentInfoListeners;
52     ListenerList<MidiInstrumentMapCountListener*> MidiInstrumentMapper::llMidiInstrumentMapCountListeners;
53     ListenerList<MidiInstrumentMapInfoListener*> MidiInstrumentMapper::llMidiInstrumentMapInfoListeners;
54 iliev 1135 int MidiInstrumentMapper::DefaultMap;
55 iliev 1130
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 iliev 1135 int MidiInstrumentMapper::GetMapCount() {
282     midiMapsMutex.Lock();
283     int i = midiMaps.size();
284     midiMapsMutex.Unlock();
285     return i;
286     }
287    
288 schoenebeck 973 int MidiInstrumentMapper::AddMap(String MapName) throw (Exception) {
289     int ID;
290     midiMapsMutex.Lock();
291     if (midiMaps.empty()) ID = 0;
292     else {
293     // get the highest existing map ID
294     uint lastIndex = (--(midiMaps.end()))->first;
295     // check if we reached the index limit
296     if (lastIndex + 1 < lastIndex) {
297     // search for an unoccupied map ID starting from 0
298     for (uint i = 0; i < lastIndex; i++) {
299     if (midiMaps.find(i) != midiMaps.end()) continue;
300     // we found an unused ID, so insert the new map there
301     ID = i;
302     goto __create_map;
303     }
304     throw Exception("Internal error: could not find unoccupied MIDI instrument map ID.");
305     }
306 iliev 976 ID = lastIndex + 1;
307 schoenebeck 973 }
308     __create_map:
309     midiMaps[ID].name = MapName;
310 iliev 1135
311     fireMidiInstrumentMapCountChanged(Maps().size());
312     // If there were no maps until now we must set a default map.
313     if (midiMaps.size() == 1) SetDefaultMap(ID);
314 schoenebeck 973 midiMapsMutex.Unlock();
315 iliev 1135
316 schoenebeck 973 return ID;
317     }
318    
319     String MidiInstrumentMapper::MapName(int Map) throw (Exception) {
320     String result;
321     midiMapsMutex.Lock();
322     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
323     if (iterMap == midiMaps.end()) {
324     midiMapsMutex.Unlock();
325     throw Exception("There is no MIDI instrument map " + ToString(Map));
326     }
327     result = iterMap->second.name;
328     midiMapsMutex.Unlock();
329     return result;
330     }
331    
332     void MidiInstrumentMapper::RenameMap(int Map, String NewName) throw (Exception) {
333     midiMapsMutex.Lock();
334     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
335     if (iterMap == midiMaps.end()) {
336     midiMapsMutex.Unlock();
337     throw Exception("There is no MIDI instrument map " + ToString(Map));
338     }
339     iterMap->second.name = NewName;
340     midiMapsMutex.Unlock();
341 iliev 1130 fireMidiInstrumentMapInfoChanged(Map);
342 schoenebeck 973 }
343    
344     void MidiInstrumentMapper::RemoveMap(int Map) {
345     midiMapsMutex.Lock();
346     midiMaps.erase(Map);
347 iliev 1135 if(Map == GetDefaultMap()) {
348     SetDefaultMap(midiMaps.empty() ? -1 : (*(midiMaps.begin())).first);
349     }
350     fireMidiInstrumentMapCountChanged(Maps().size());
351 schoenebeck 973 midiMapsMutex.Unlock();
352     }
353    
354     void MidiInstrumentMapper::RemoveAllMaps() {
355     midiMapsMutex.Lock();
356     midiMaps.clear();
357 iliev 1135 SetDefaultMap(-1);
358     fireMidiInstrumentMapCountChanged(Maps().size());
359 schoenebeck 973 midiMapsMutex.Unlock();
360     }
361    
362 iliev 1135 int MidiInstrumentMapper::GetDefaultMap() {
363     midiMapsMutex.Lock();
364     int i = DefaultMap;
365     midiMapsMutex.Unlock();
366     return i;
367     }
368    
369     void MidiInstrumentMapper::SetDefaultMap(int MapId) {
370     midiMapsMutex.Lock();
371     DefaultMap = MapId;
372     midiMapsMutex.Unlock();
373    
374     if (MapId != -1) fireMidiInstrumentMapInfoChanged(MapId);
375     }
376    
377 schoenebeck 973 optional<MidiInstrumentMapper::entry_t> MidiInstrumentMapper::GetEntry(int Map, midi_prog_index_t Index) {
378 schoenebeck 947 optional<entry_t> result;
379 schoenebeck 973 midiMapsMutex.Lock();
380     std::map<int,MidiInstrumentMap>::iterator iterMap = midiMaps.find(Map);
381     if (iterMap != midiMaps.end()) { // map found
382     std::map<midi_prog_index_t,private_entry_t>::iterator iterEntry = iterMap->second.find(Index);
383     if (iterEntry != iterMap->second.end()) {
384     entry_t entry;
385     entry.EngineName = iterEntry->second.EngineName;
386     entry.InstrumentFile = iterEntry->second.InstrumentFile;
387     entry.InstrumentIndex = iterEntry->second.InstrumentIndex;
388     entry.Volume = iterEntry->second.Volume;
389     //TODO: for now we skip the LoadMode and Name entry here, since we don't need it in the MidiInputPort
390     result = entry;
391     }
392 schoenebeck 947 }
393 schoenebeck 973 midiMapsMutex.Unlock();
394 schoenebeck 947 return result;
395     }
396    
397     } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC